Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DTrackCandidate_factory_CDC.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DTrackCandidate_factory_CDC.cc
4 // Created: Thu Sep 6 14:47:48 EDT 2007
5 // Creator: davidl (on Darwin Amelia.local 8.10.1 i386)
6 //
7 
9 #include <cmath>
10 #include <JANA/JCalibration.h>
11 
12 #define BeamRMS 0.5
13 #define EPS 1e-3
14 
15 #define TWO(c) (0x1u << (c))
16 #define MASK(c) ((unsigned int)(-1)) / (TWO(TWO(c)) + 1u)
17 #define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c))
18 
19 #ifndef M_TWO_PI
20 #define M_TWO_PI 6.28318530717958647692
21 #endif
22 
23 using namespace std;
24 
25 inline int bitcount(unsigned int n)
26 {
27  n = COUNT(n, 0);
28  n = COUNT(n, 1);
29  n = COUNT(n, 2);
30  n = COUNT(n, 3);
31  n = COUNT(n, 4);
32  //n = COUNT(n, 5); for 64-bit integers
33  return n;
34 }
35 
37 {
38  // use the ring number to sort by R(decreasing) and then straw(increasing)
39  if(hit1->hit->wire->ring == hit2->hit->wire->ring)
40  return hit1->hit->wire->straw < hit2->hit->wire->straw;
41  return hit1->hit->wire->ring > hit2->hit->wire->ring;
42 }
43 
45 {
46  // largest weighted fit chisq/ndf is first
47  return (locTrackCircle1->dWeightedChiSqPerDF > locTrackCircle2->dWeightedChiSqPerDF);
48 }
49 
51 {
52  // smallest weighted theta/z chisq/ndf is first
53  return (locTrackCircle1->dWeightedChiSqPerDF_Stereo < locTrackCircle2->dWeightedChiSqPerDF_Stereo);
54 }
55 
57 {
58  return (locIntersection1.perp2 < locIntersection2.perp2);
59 }
60 
61 inline bool CDCSort_DeltaPhis(const pair<DTrackCandidate_factory_CDC::DCDCTrkHit*, double>& locDeltaPhiPair1, const pair<DTrackCandidate_factory_CDC::DCDCTrkHit*, double>& locDeltaPhiPair2)
62 {
63  //smallest delta-phi is first
64  return (locDeltaPhiPair1.second < locDeltaPhiPair2.second);
65 }
66 
68 
69 }
70 
71 
72 //------------------
73 // init
74 //------------------
76 {
77  DEBUG_LEVEL = 0;
78  MAX_DCDCTrkHitPoolSize = 200;
79  MAX_DCDCSuperLayerSeedPoolSize = 50;
80  MAX_HelicalFitPoolSize = 100;
81  MAX_DCDCTrackCirclePoolSize = 100;
82 
83  MAX_ALLOWED_CDC_HITS = 10000;
84  MAX_ALLOWED_TRACK_CIRCLES = 5000;
85  MAX_HIT_DIST = 4.0; // cm //each straw is 5/8in (1.5875 cm) in diameter
86  MAX_HIT_DIST2 = MAX_HIT_DIST*MAX_HIT_DIST;
87 
88  //when linking DCDCRingSeed's together to form DCDCSuperLayerSeed's, allow skipping of rings
89  //for example, say there are hits in ring 1 and ring 3, but none in ring 2 because the particle didn't deposit enough energy.
90  //setting MAX_NUM_RINGSEED_RINGS_SKIPABLE >= 1 will recover these cases
91  MAX_NUM_RINGSEED_RINGS_SKIPABLE = 1;
92 
93  MIN_SEED_HITS = 2;
94 
95  // to be labeled as a potential/definite spiral turn (in/out-wards), the following conditions need to be met (where appropriate):
96  MIN_STRAWS_POTENTIAL_SPIRAL_TURN = 4; //minimum number of straws in a DCDCRingSeed necessary to be labeled as a potential spiral turn (in/out-wards)
97  MIN_STRAWS_DEFINITE_SPIRAL_TURN = 6; //minimum number of straws in a DCDCRingSeed necessary to be labeled as a definite spiral turn (in/out-wards)
98  MIN_STRAWS_ADJACENT_TO_SPIRAL_TURN = 3; // in some cases, this is the minimum number of straws in a DCDCRingSeed that is adjacent to the spiral turn (in/out-wards)
99  // if a spiral turn occurs between rings or outside the CDC, the below is the max # of straws that can be between two DCDCRingSeed's in the adjacent ring
100  // the two DCDCRingSeed's would be in different super layer seeds
101  MAX_STRAWS_BETWEEN_LINK_SPIRAL_TURN = 6;
102 
103  //within a super layer, if the number of seeds in a region of width SEED_DENSITY_BIN_STRAW_WIDTH is greater than MAX_SEEDS_IN_STRAW_BIN, reject all seeds passing through this region
104  //note that since the # of straws increases with ring #, the region width is technically computed as a phi region:
105  //from phi of straw 'N' in the first ring of a given super layer, to the phi of straw 'N + DENSITY_BIN_STRAW_WIDTH - 1'
106  SEED_DENSITY_BIN_STRAW_WIDTH = 8;
107  MAX_SEEDS_IN_STRAW_BIN = 15;
108 
109  //when true, will allow linking of super layer seeds to skip a super layer (in case there is a dead HV board there)
110  //note that this feature is not fully tested!!
111  ENABLE_DEAD_HV_BOARD_LINKING = false;
112 
113  //don't allow new track seeds to start after this super layer
114  //track seeds could start late if track is a decay product, or HV board is dead
115  //this is to prevent tracks forming that are complete garbage (e.g. a spiral craziness, knockout electrons re-entering the CDC from the BCAL, etc.)
116  MAX_SUPERLAYER_NEW_TRACK = 4;
117 
118  // the maximum # of hits allowed to be shared between the axial super layer seeds of DCDCTrackCircle's
119  // if > than this amount, the track with the larger circle-fit weighted-chisq/ndf will be rejected
120  MAX_COMMON_HIT_FRACTION = 0.49; //reject if exactly half
121 
122  MAX_DRIFT_TIME = 1000.0; // ns
123  MAX_SEED_TIME_DIFF = 1000.0; // ns
124 
125  // used for identifying arms of a spiral: can be true if the centers of the fit circles are close together (relative to their difference from the origin)
126  MIN_CIRCLE_ASYMMETRY = 0.10;
127 
128  // when calculating the final theta/z, include at least this many stereo hits for the calculation
129  // don't want to include stereo hits whose projections onto the track circle are too far away
130  MIN_PRUNED_STEREO_HITS = 4;
131 
132  // when searching for unused axial hits to add to the track, require that the hit be within this #-degrees in phi to the circle fit
133  MAX_UNUSED_HIT_LINK_ANGLE = 10.0; //degrees
134 
135  TARGET_Z = 65.0;
136  VERTEX_Z_MIN = -100.0;
137  VERTEX_Z_MAX = 200.0;
138 
139  cdchits_by_superlayer.resize(7);
140  dSuperLayerSeeds.resize(7);
141  for(unsigned int loc_i = 0; loc_i < 7; ++loc_i)
142  superlayer_boundaries.push_back(4*(1 + loc_i));
143 
144  dNumStrawsPerRing.resize(28);
145 
146  dNumSeedDensityPhiBins = 360;
147 
148  return NOERROR;
149 }
150 
151 //------------------
152 // brun
153 //------------------
154 jerror_t DTrackCandidate_factory_CDC::brun(JEventLoop *locEventLoop, int32_t runnumber)
155 {
156  gPARMS->SetDefaultParameter("TRKFIND:DEBUG_LEVEL", DEBUG_LEVEL);
157  gPARMS->SetDefaultParameter("TRKFIND:MAX_ALLOWED_CDC_HITS", MAX_ALLOWED_CDC_HITS);
158  gPARMS->SetDefaultParameter("TRKFIND:MAX_ALLOWED_TRACK_CIRCLES", MAX_ALLOWED_TRACK_CIRCLES);
159  gPARMS->SetDefaultParameter("TRKFIND:MAX_HIT_DIST", MAX_HIT_DIST);
160  gPARMS->SetDefaultParameter("TRKFIND:MAX_NUM_RINGSEED_RINGS_SKIPABLE", MAX_NUM_RINGSEED_RINGS_SKIPABLE);
161  gPARMS->SetDefaultParameter("TRKFIND:MIN_SEED_HITS", MIN_SEED_HITS);
162  gPARMS->SetDefaultParameter("TRKFIND:MIN_STRAWS_POTENTIAL_SPIRAL_TURN", MIN_STRAWS_POTENTIAL_SPIRAL_TURN);
163  gPARMS->SetDefaultParameter("TRKFIND:MIN_STRAWS_DEFINITE_SPIRAL_TURN", MIN_STRAWS_DEFINITE_SPIRAL_TURN);
164  gPARMS->SetDefaultParameter("TRKFIND:MIN_STRAWS_ADJACENT_TO_SPIRAL_TURN", MIN_STRAWS_ADJACENT_TO_SPIRAL_TURN);
165  gPARMS->SetDefaultParameter("TRKFIND:MAX_STRAWS_BETWEEN_LINK_SPIRAL_TURN", MAX_STRAWS_BETWEEN_LINK_SPIRAL_TURN);
166  gPARMS->SetDefaultParameter("TRKFIND:SEED_DENSITY_BIN_STRAW_WIDTH", SEED_DENSITY_BIN_STRAW_WIDTH);
167  gPARMS->SetDefaultParameter("TRKFIND:MAX_SEEDS_IN_STRAW_BIN", MAX_SEEDS_IN_STRAW_BIN);
168  gPARMS->SetDefaultParameter("TRKFIND:ENABLE_DEAD_HV_BOARD_LINKING", ENABLE_DEAD_HV_BOARD_LINKING);
169  gPARMS->SetDefaultParameter("TRKFIND:MAX_SUPERLAYER_NEW_TRACK", MAX_SUPERLAYER_NEW_TRACK);
170  gPARMS->SetDefaultParameter("TRKFIND:MAX_COMMON_HIT_FRACTION", MAX_COMMON_HIT_FRACTION);
171  gPARMS->SetDefaultParameter("TRKFIND:MIN_CIRCLE_ASYMMETRY", MIN_CIRCLE_ASYMMETRY);
172  gPARMS->SetDefaultParameter("TRKFIND:MAX_DRIFT_TIME", MAX_DRIFT_TIME);
173  gPARMS->SetDefaultParameter("TRKFIND:MAX_SEED_TIME_DIFF", MAX_SEED_TIME_DIFF);
174  gPARMS->SetDefaultParameter("TRKFIND:MIN_PRUNED_STEREO_HITS", MIN_PRUNED_STEREO_HITS);
175  gPARMS->SetDefaultParameter("TRKFIND:MAX_UNUSED_HIT_LINK_ANGLE", MAX_UNUSED_HIT_LINK_ANGLE);
176  gPARMS->SetDefaultParameter("TRKFIND:VERTEX_Z_MIN", VERTEX_Z_MIN);
177  gPARMS->SetDefaultParameter("TRKFIND:VERTEX_Z_MAX", VERTEX_Z_MAX);
178 
179  MAX_HIT_DIST2 = MAX_HIT_DIST*MAX_HIT_DIST;
180 
181  DApplication* locApplication = dynamic_cast<DApplication*>(locEventLoop->GetJApplication());
182  dMagneticField = locApplication->GetBfield(runnumber);
183  dFactorForSenseOfRotation=(dMagneticField->GetBz(0.,0.,65.)>0.)?-1.:1.;
184 
185  const DGeometry *locGeometry = locApplication->GetDGeometry(runnumber);
186  JCalibration *jcalib = locApplication->GetJCalibration(runnumber);
187  map<string, double> targetparms;
188  if (jcalib->Get("TARGET/target_parms",targetparms)==false){
189  TARGET_Z = targetparms["TARGET_Z_POSITION"];
190  }
191  else{
192  locGeometry->GetTargetZ(TARGET_Z);
193  }
194 
195  // Get the CDC wire table from the XML
196  vector<vector<DCDCWire*> > locCDCWires;
197  locGeometry->GetCDCWires(locCDCWires);
198  for(size_t loc_i = 0; loc_i < locCDCWires.size(); ++loc_i)
199  dNumStrawsPerRing[loc_i] = locCDCWires[loc_i].size();
200 
201  // Clean up after using wire map
202  for (size_t i=0;i<locCDCWires.size();i++){
203  for (size_t j=0;j<locCDCWires[i].size();j++){
204  delete locCDCWires[i][j];
205  }
206  }
207 
208  return NOERROR;
209 }
210 
211 //------------------
212 // evnt
213 //------------------
214 jerror_t DTrackCandidate_factory_CDC::evnt(JEventLoop *locEventLoop, uint64_t eventnumber)
215 {
216  // Reset
217  dRejectedPhiRegions.clear();
218  dStereoHitNumUsedMap.clear();
219  for(unsigned int loc_i = 0; loc_i < 7; ++loc_i)
220  dSuperLayerSeeds[loc_i].clear();
221 
222  // Reset in case didn't clear before exiting event evaluation on last event.
223  Reset_Pools();
224 
225  // Get CDC hits
226  if(Get_CDCHits(locEventLoop) != NOERROR)
227  {
228  Reset_Pools();
229  return RESOURCE_UNAVAILABLE;
230  }
231 
232  // Build Super Layer Seeds
233  for(unsigned int loc_i = 0; loc_i < 7; ++loc_i)
234  {
235  if(DEBUG_LEVEL > 3)
236  cout << "Find Seeds, Super Layer = " << loc_i + 1 << endl;
237  Find_SuperLayerSeeds(cdchits_by_superlayer[loc_i], loc_i + 1);
238  Reject_SuperLayerSeeds_HighSeedDensity(loc_i + 1);
239  }
240  // Search for Spiral Links in and between super layer seeds
241  Set_SpiralLinkParams();
242  if(DEBUG_LEVEL > 5)
243  {
244  cout << "init super layers" << endl;
245  Print_SuperLayerSeeds();
246  }
247 
248  // Build DCDCTrackCircle objects (each corresponds to (at most) one track):
249  vector<DCDCTrackCircle*> locCDCTrackCircles;
250  bool locStatusFlag = Build_TrackCircles(locCDCTrackCircles);
251  if(!locStatusFlag)
252  {
253  //SHOULD SET JEVENT STATUS BIT HERE!!!
254  Reset_Pools();
255  return OBJECT_NOT_AVAILABLE;
256  }
257  if(locCDCTrackCircles.empty())
258  {
259  Reset_Pools();
260  return NOERROR;
261  }
262  Handle_StereoAndFilter(locCDCTrackCircles, false); //false: not final pass: filter seeds, don't reject seeds with no stereo hits (will add unused below), etc.
263 
264  // If the last super layer of a track is not 7, search for lone, unused hits on the next super layer and add them to the track
265  // Only add them if they are close enough to the track circle fit
266  Add_UnusedHits(locCDCTrackCircles);
267 
268  // using axial on the track, redo the circle fit and re-calc theta-z
269  // This is for when extra hits are picked up by Add_UnusedHits, and for including midpoints between SL2/SL3 & SL5/SL6
270  //fit circles will reject fits if they aren't very good //false: fit all circles //true: add intersections between stereo layers
271  Fit_Circles(locCDCTrackCircles, false, true); //will reject fits if they aren't very good
272  if(DEBUG_LEVEL > 5)
273  {
274  cout << "final fit track circles" << endl;
275  Print_TrackCircles(locCDCTrackCircles);
276  }
277  stable_sort(locCDCTrackCircles.begin(), locCDCTrackCircles.end(), CDCSortByChiSqPerNDFDecreasing); //sort by circle-fit weighted chisq/ndf (largest first)
278 
279  Handle_StereoAndFilter(locCDCTrackCircles, true); //true: final pass: don't need to filter any more, get improved theta-z (although will reject if bad/no theta/z)
280  if(DEBUG_LEVEL > 5)
281  {
282  cout << "final track circles" << endl;
283  Print_TrackCircles(locCDCTrackCircles);
284  }
285 
286  // Create track candidates (as long as p > 0!!)
287  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
288  Create_TrackCandidiate(locCDCTrackCircles[loc_i]);
289 
290  // Reset memory before exiting event evaluation.
291  Reset_Pools();
292 
293  return NOERROR;
294 }
295 
296 //------------------
297 // Reset_Pools
298 //------------------
300 {
301  // delete pool contents if too large, preventing memory-leakage-like behavor.
302  if(dCDCTrkHitPool_All.size() > MAX_DCDCTrkHitPoolSize)
303  {
304  for(size_t loc_i = MAX_DCDCTrkHitPoolSize; loc_i < dCDCTrkHitPool_All.size(); ++loc_i)
305  delete dCDCTrkHitPool_All[loc_i];
306  dCDCTrkHitPool_All.resize(MAX_DCDCTrkHitPoolSize);
307  }
308  dCDCTrkHitPool_Available = dCDCTrkHitPool_All;
309 
310  if(dCDCSuperLayerSeedPool_All.size() > MAX_DCDCSuperLayerSeedPoolSize)
311  {
312  for(size_t loc_i = MAX_DCDCSuperLayerSeedPoolSize; loc_i < dCDCSuperLayerSeedPool_All.size(); ++loc_i)
313  delete dCDCSuperLayerSeedPool_All[loc_i];
314  dCDCSuperLayerSeedPool_All.resize(MAX_DCDCSuperLayerSeedPoolSize);
315  }
316  dCDCSuperLayerSeedPool_Available = dCDCSuperLayerSeedPool_All;
317 
318  if(dHelicalFitPool_All.size() > MAX_HelicalFitPoolSize)
319  {
320  for(unsigned int loc_i = MAX_HelicalFitPoolSize; loc_i < dHelicalFitPool_All.size(); ++loc_i)
321  delete dHelicalFitPool_All[loc_i];
322  dHelicalFitPool_All.resize(MAX_HelicalFitPoolSize);
323  }
324  dHelicalFitPool_Available = dHelicalFitPool_All;
325 
326  if(dCDCTrackCirclePool_All.size() > MAX_DCDCTrackCirclePoolSize)
327  {
328  for(size_t loc_i = MAX_DCDCTrackCirclePoolSize; loc_i < dCDCTrackCirclePool_All.size(); ++loc_i)
329  delete dCDCTrackCirclePool_All[loc_i];
330  dCDCTrackCirclePool_All.resize(MAX_DCDCTrackCirclePoolSize);
331  }
332  dCDCTrackCirclePool_Available = dCDCTrackCirclePool_All;
333 }
334 
336 {
337  DCDCTrkHit* locCDCTrkHit;
338  if(dCDCTrkHitPool_Available.empty())
339  {
340  locCDCTrkHit = new DCDCTrkHit;
341  dCDCTrkHitPool_All.push_back(locCDCTrkHit);
342  }
343  else
344  {
345  locCDCTrkHit = dCDCTrkHitPool_Available.back();
346  dCDCTrkHitPool_Available.pop_back();
347  }
348  locCDCTrkHit->Reset();
349  return locCDCTrkHit;
350 }
351 
353 {
354  DCDCSuperLayerSeed* locCDCSuperLayerSeed;
355  if(dCDCSuperLayerSeedPool_Available.empty())
356  {
357  locCDCSuperLayerSeed = new DCDCSuperLayerSeed;
358  dCDCSuperLayerSeedPool_All.push_back(locCDCSuperLayerSeed);
359  }
360  else
361  {
362  locCDCSuperLayerSeed = dCDCSuperLayerSeedPool_Available.back();
363  dCDCSuperLayerSeedPool_Available.pop_back();
364  }
365  locCDCSuperLayerSeed->Reset();
366  return locCDCSuperLayerSeed;
367 }
368 
370 {
371  DHelicalFit* locHelicalFit;
372  if(dHelicalFitPool_Available.empty())
373  {
374  locHelicalFit = new DHelicalFit;
375  dHelicalFitPool_All.push_back(locHelicalFit);
376  }
377  else
378  {
379  locHelicalFit = dHelicalFitPool_Available.back();
380  dHelicalFitPool_Available.pop_back();
381  }
382  locHelicalFit->Reset();
383  return locHelicalFit;
384 }
385 
387 {
388  DCDCTrackCircle* locCDCTrackCircle;
389  if(dCDCTrackCirclePool_Available.empty())
390  {
391  locCDCTrackCircle = new DCDCTrackCircle;
392  dCDCTrackCirclePool_All.push_back(locCDCTrackCircle);
393  }
394  else
395  {
396  locCDCTrackCircle = dCDCTrackCirclePool_Available.back();
397  dCDCTrackCirclePool_Available.pop_back();
398  }
399  locCDCTrackCircle->Reset();
400  return locCDCTrackCircle;
401 }
402 
403 //------------------
404 // Get_CDCHits
405 //------------------
407 {
408  // Get the "raw" hits. These already have the wire associated with them.
409  vector<const DCDCTrackHit*> cdctrackhits;
410  loop->Get(cdctrackhits);
411  dNumCDCHits = cdctrackhits.size();
412 
413  // If there are no hits, then bail now
414  if(cdctrackhits.empty())
415  return RESOURCE_UNAVAILABLE;
416 
417  // If there are too many hits, bail with a warning message
418  if(cdctrackhits.size() > MAX_ALLOWED_CDC_HITS)
419  {
420  cout << "Too many hits in CDC (" <<cdctrackhits.size() << ", max = " << MAX_ALLOWED_CDC_HITS << ")! Track finding in CDC bypassed for event " << loop->GetJEvent().GetEventNumber() << endl;
421  cdctrackhits.clear();
422  return UNRECOVERABLE_ERROR;
423  }
424 
425  // clear old hits
426  cdctrkhits.clear();
427  for(unsigned int i = 0; i < cdchits_by_superlayer.size(); i++)
428  cdchits_by_superlayer[i].clear();
429 
430  // Create DCDCTrkHit objects out of these.
431  int oldwire = -1;
432  for(size_t i = 0; i< cdctrackhits.size(); ++i)
433  {
434  // Add to "master" list
435  // ONLY FIRST HIT OF A WIRE
436  int newwire = cdctrackhits[i]->wire->ring*1000 + cdctrackhits[i]->wire->straw;
437  if(newwire == oldwire)
438  continue;
439  oldwire = newwire;
440 
441  if(DEBUG_LEVEL > 40)
442  cout << "adding ring, straw = " << cdctrackhits[i]->wire->ring << ", " << cdctrackhits[i]->wire->straw << endl;
443 
444  // Add to "master" list
445  DCDCTrkHit* cdctrkhit = Get_Resource_CDCTrkHit();
446  cdctrkhit->index = i;
447  cdctrkhit->hit = cdctrackhits[i];
448  cdctrkhit->flags = NONE;
449  cdctrkhit->flags |= NOISE; // (see below)
450  cdctrkhits.push_back(cdctrkhit);
451 
452  // Sort into list of hits by superlayer
453  for(size_t j = 0; j < superlayer_boundaries.size(); ++j)
454  {
455  if(cdctrkhit->hit->wire->ring <= int(superlayer_boundaries[j]))
456  {
457  cdchits_by_superlayer[j].push_back(cdctrkhit);
458  break;
459  }
460  }
461  }
462 
463  // Sort the individual superlayer lists by decreasing values of R
464  for(size_t i = 0; i < cdchits_by_superlayer.size(); ++i)
465  stable_sort(cdchits_by_superlayer[i].begin(), cdchits_by_superlayer[i].end(), CDCSortByRdecreasing);
466 
467  // Filter out noise hits. All hits are initially flagged as "noise".
468  // Hits with a neighbor within MAX_HIT_DIST have their noise flags cleared.
469  // Also flag hits as out-of-time if their drift time is too large
470  for(size_t i = 0; i < cdctrkhits.size(); ++i)
471  {
472  DCDCTrkHit *trkhit1 = cdctrkhits[i];
473  if(trkhit1->hit->tdrift > MAX_DRIFT_TIME)
474  trkhit1->flags |= OUT_OF_TIME;
475  if(!(trkhit1->flags & NOISE))
476  continue; // this hit already not marked for noise
477  for(size_t j = 0; j < cdctrkhits.size(); ++j)
478  {
479  if(j == i)
480  continue;
481  double d2 = trkhit1->Dist2(cdctrkhits[j]);
482  if(d2 > 9.0*MAX_HIT_DIST2)
483  continue;
484  trkhit1->flags &= ~NOISE;
485  cdctrkhits[j]->flags &= ~NOISE;
486  break;
487  }
488  }
489 
490  return NOERROR;
491 }
492 
493 /*********************************************************************************************************************************************************************/
494 /********************************************************************** BUILD SUPER LAYER SEEDS **********************************************************************/
495 /*********************************************************************************************************************************************************************/
496 
497 //---------------------
498 // Find_SuperLayerSeeds
499 //---------------------
500 void DTrackCandidate_factory_CDC::Find_SuperLayerSeeds(vector<DCDCTrkHit*>& locSuperLayerHits, unsigned int locSuperLayer)
501 {
502  // Sort through hits ring by ring to find DCDCRingSeed's from neighboring wires in the same ring.
503  // What we want is a list of DCDCRingSeed's for each ring, which will then be combined to form DCDCSuperLayerSeeds
504  // Each DCDCRingSeed is a list of adjacent hits ordered by straw number.
505  // If a DCDCRingSeed crosses the straw = 1 barrier:
506  // Then the first hit is the smallest straw with phi > pi, and the last hit is the largest straw with phi < pi
507 
508  // Clear DCDCSuperLayerSeed's
509  vector<DCDCSuperLayerSeed*>& locSuperLayerSeeds = dSuperLayerSeeds[locSuperLayer - 1];
510  locSuperLayerSeeds.clear();
511 
512  DCDCRingSeed locCDCRingSeed;
513  vector<DCDCRingSeed> locCDCRingSeeds; //list of DCDCRingSeed's in a given ring
514  vector<vector<DCDCRingSeed> > rings; //1st dimension is ring, 2nd dimension is DCDCRingSeed's in that ring
515  int last_ring = -1;
516 
517  for(size_t i = 0; i < locSuperLayerHits.size(); ++i)
518  {
519  DCDCTrkHit *trkhit = locSuperLayerHits[i];
520  if(DEBUG_LEVEL > 20)
521  cout << "track hit ring, straw = " << trkhit->hit->wire->ring << ", " << trkhit->hit->wire->straw << endl;
522 
523  // Check if ring number has changed.
524  if(trkhit->hit->wire->ring != last_ring)
525  {
526  if(DEBUG_LEVEL > 20)
527  cout << "new ring, last ring = " << trkhit->hit->wire->ring << ", " << last_ring << endl;
528  //ring # has changed: save the current DCDCRingSeed (from the previous ring) (if not empty)
529  if(!locCDCRingSeed.hits.empty())
530  locCDCRingSeeds.push_back(locCDCRingSeed);
531  //if > 1 DCDCRingSeed on the previous ring: compare first and last DCDCRingSeeds
532  //if they are adjacent (extending through the straw = 1 boundary): merge DCDCRingSeeds
533  if(locCDCRingSeeds.size() > 1)
534  {
535  unsigned int locMinStraw = locCDCRingSeeds[0].hits[0]->hit->wire->straw;
536  unsigned int locMaxStraw = locCDCRingSeeds[locCDCRingSeeds.size() - 1].hits[locCDCRingSeeds[locCDCRingSeeds.size() - 1].hits.size() - 1]->hit->wire->straw;
537  unsigned int locNumStrawsInRing = dNumStrawsPerRing[locCDCRingSeeds[0].hits[0]->hit->wire->ring - 1];
538  if((locMinStraw + locNumStrawsInRing - locMaxStraw) <= 1) //merge ringseeds
539  {
540  if(DEBUG_LEVEL > 20)
541  cout << "straw boundary: merge ringseeds" << endl;
542  locCDCRingSeeds[0].hits.insert(locCDCRingSeeds[0].hits.begin(), locCDCRingSeeds[locCDCRingSeeds.size() - 1].hits.begin(), locCDCRingSeeds[locCDCRingSeeds.size() - 1].hits.end());
543  //insert at beginning: straws now arranged as: ..., N - 2, N - 1, N, 1, 2, 3, ...
544  locCDCRingSeeds.pop_back();
545  }
546  }
547  //if there was at least one DCDCRingSeed found on the previous ring, save it in the 2d vector
548  if(!locCDCRingSeeds.empty())
549  rings.push_back(locCDCRingSeeds);
550  if(DEBUG_LEVEL > 3)
551  cout << " ringseed hits:" << locCDCRingSeed.hits.size() << " locCDCRingSeeds:" << locCDCRingSeeds.size() << endl;
552  //reset for finding the next group of hits
553  locCDCRingSeeds.clear();
554  locCDCRingSeed.hits.clear();
555  //save this hit and continue
556  locCDCRingSeed.hits.push_back(trkhit);
557  locCDCRingSeed.ring = trkhit->hit->wire->ring;
558  locCDCRingSeed.linked = false;
559  last_ring = trkhit->hit->wire->ring;
560  continue;
561  }
562 
563  // Check if this hit is a neighbor of the last hit added to the ringseed
564  if((unsigned int)abs(locCDCRingSeed.hits[locCDCRingSeed.hits.size() - 1]->hit->wire->straw - trkhit->hit->wire->straw) > 1)
565  {
566  //not a neighbor: save old and create new ringseed
567  if(DEBUG_LEVEL > 20)
568  cout << "straw diff" << endl;
569  if(!locCDCRingSeed.hits.empty())
570  locCDCRingSeeds.push_back(locCDCRingSeed);
571  if(DEBUG_LEVEL > 3)
572  cout << "ringseed hits: " << locCDCRingSeed.hits.size() << endl;
573  locCDCRingSeed.hits.clear();
574  locCDCRingSeed.linked = false;
575  }
576 
577  locCDCRingSeed.hits.push_back(trkhit);
578  if(DEBUG_LEVEL > 20)
579  cout << "push back hit straw = " << trkhit->hit->wire->straw << endl;
580  }
581  //save final seeds, check if need to merge
582  if(!locCDCRingSeed.hits.empty())
583  locCDCRingSeeds.push_back(locCDCRingSeed);
584  if(locCDCRingSeeds.size() > 1)
585  {
586  //compare first and last ringseeds: if ringseed extends through straw boundary, merge ringseeds
587  unsigned int locMinStraw = locCDCRingSeeds[0].hits[0]->hit->wire->straw;
588  unsigned int locMaxStraw = locCDCRingSeeds[locCDCRingSeeds.size() - 1].hits[locCDCRingSeeds[locCDCRingSeeds.size() - 1].hits.size() - 1]->hit->wire->straw;
589  unsigned int locNumStrawsInRing = dNumStrawsPerRing[locCDCRingSeeds[0].hits[0]->hit->wire->ring - 1];
590  if((locMinStraw + locNumStrawsInRing - locMaxStraw) <= 1) //merge ringseeds
591  {
592  if(DEBUG_LEVEL > 20)
593  cout << "straw boundary: merge ringseeds" << endl;
594  locCDCRingSeeds[0].hits.insert(locCDCRingSeeds[0].hits.begin(), locCDCRingSeeds[locCDCRingSeeds.size() - 1].hits.begin(), locCDCRingSeeds[locCDCRingSeeds.size() - 1].hits.end());
595  //insert at beginning: straws now arranged as: ..., N - 2, N - 1, N, 1, 2, 3, ...
596  locCDCRingSeeds.pop_back();
597  }
598  }
599  if(!locCDCRingSeeds.empty())
600  rings.push_back(locCDCRingSeeds);
601  if(DEBUG_LEVEL > 3)
602  cout << " ringseed hits:" << locCDCRingSeed.hits.size() << " ringseeds:" << locCDCRingSeeds.size() << endl;
603  if(DEBUG_LEVEL > 3)
604  cout << "rings: " << rings.size() << endl;
605 
606  // Print all DCDCRingSeeds to screen
607  if(DEBUG_LEVEL > 45)
608  {
609  for(size_t i = 0; i < rings.size(); ++i)
610  {
611  for(size_t k = 0; k < rings[i].size(); ++k)
612  {
613  cout << "hits for ringseed ring, seed indices " << i << ", " << k << ":" << endl;
614  for(size_t j = 0; j < rings[i][k].hits.size(); ++j)
615  cout << "wire ring, straw = " << rings[i][k].hits[j]->hit->wire->ring << ", " << rings[i][k].hits[j]->hit->wire->straw << endl;
616  }
617  }
618  }
619 
620  // If we have no rings, then there must be no super layer seeds. Bail now.
621  if(rings.empty())
622  return;
623 
624  // Loop over rings, creating DCDCSuperLayerSeed's from adjacent rings
625  for(ringiter ring = rings.begin(); ring != rings.end(); ++ring)
626  {
627  vector<DCDCRingSeed>& locCDCRingSeeds = *ring;
628  ringiter next_ring = ring;
629  ++next_ring;
630 
631  // Loop over ringseeds of this ring
632  for(size_t j = 0; j < locCDCRingSeeds.size(); ++j)
633  {
634  if(locCDCRingSeeds[j].linked)
635  continue;
636 
637  // This ringseed hasn't been used in a DCDCSuperLayerSeed yet. Start a new seed with it.
638  vector<DCDCRingSeed*> parent;
639  parent.push_back(&locCDCRingSeeds[j]);
640  Link_RingSeeds(parent, next_ring, rings.end(), locSuperLayer, 0);
641  }
642  }
643 
644  // Set wire orientations
645  for(size_t loc_i = 0; loc_i < locSuperLayerSeeds.size(); ++loc_i)
646  {
647  locSuperLayerSeeds[loc_i]->dSuperLayer = locSuperLayer;
648  locSuperLayerSeeds[loc_i]->dSeedIndex = loc_i;
649  if((locSuperLayer == 7) || (locSuperLayer == 4) || (locSuperLayer == 1))
650  locSuperLayerSeeds[loc_i]->dWireOrientation = WIRE_DIRECTION_AXIAL;
651  else if((locSuperLayer == 2) || (locSuperLayer == 6))
652  locSuperLayerSeeds[loc_i]->dWireOrientation = WIRE_DIRECTION_STEREOLEFT;
653  else
654  locSuperLayerSeeds[loc_i]->dWireOrientation = WIRE_DIRECTION_STEREORIGHT;
655  }
656 }
657 
658 //---------------
659 // Link_RingSeeds
660 //---------------
661 void DTrackCandidate_factory_CDC::Link_RingSeeds(vector<DCDCRingSeed*>& parent, ringiter ring, ringiter ringend, unsigned int locSuperLayer, unsigned int locNumPreviousRingsWithoutHit)
662 {
663  /// Combine DCDCRingSeed's from rings into DCDCSuperLayerSeed's
664  ///
665  /// This a a re-entrant routine (i.e. it calls itself recursively). Upon
666  /// entry, <i>parent</i> contains a list of pointers to all of the ringseeds
667  /// from the rings outside of <i>ring</i> that are to be combined into
668  /// a seed. This will search through all ringseeds of <i>ring</i> and if
669  /// any are found that can extend the parent, a copy of parent is made,
670  /// the current ringseed of this ring is added to it, and then it is
671  /// passed on to another call to this routine. If no matches are found,
672  /// then it will try skipping a ring to find matches (if enabled).
673  /// If still no matches are found (which will be the case for the outer-most ring), then
674  /// the ringseeds in <i>parent</i> will be combined into a single DCDCSuperLayerSeed.
675 
676  // Make sure parent has at least one ringseed
677  if(parent.empty())
678  {
679  cout << "parent has no ringseeds!!" << endl;
680  return;
681  }
682 
683  // Set flag to keep track of whether this is the end of the seed or not
684  bool seed_extended = false;
685  if(ring != ringend)
686  {
687  // Last ringseed in parent list is the one we need to compare to
688  DCDCRingSeed *parent_ringseed = parent[parent.size() - 1];
689  double r_parent = parent_ringseed->hits[0]->hit->wire->origin.Perp();
690 
691  // Loop over ringseeds in this ring
692  vector<DCDCRingSeed> &locCDCRingSeeds = (*ring);
693  ++ring; // increment ring iterator to point to next level down in case we recall ouself below
694 
695  for(size_t i = 0; i < locCDCRingSeeds.size(); ++i)
696  {
697  // Calculate the transverse (to the beamline) distance between the two DCDCRingSeed's
698  double dr = r_parent - locCDCRingSeeds[i].hits[0]->hit->wire->origin.Perp();
699  double locTransverseDist2 = fabs(MinDist2(locCDCRingSeeds[i], *parent_ringseed) - dr*dr);
700  // Check if this ringseed is close enough to the parent's to link them together
701  if(DEBUG_LEVEL > 20)
702  cout << "ring1, ring2, locTransverseDist2, MAX_HIT_DIST2, dr*dr = " << locCDCRingSeeds[i].hits[0]->hit->wire->ring << ", " << parent_ringseed->hits[0]->hit->wire->ring << ", " << locTransverseDist2 << ", " << MAX_HIT_DIST2 << ", " << dr*dr << endl;
703  if(locTransverseDist2 < MAX_HIT_DIST2)
704  {
705  // link them together
706  vector<DCDCRingSeed*> myparent = parent;
707  myparent.push_back(&locCDCRingSeeds[i]);
708  locCDCRingSeeds[i].linked = true;
709  // recursive call: try to link this grouping of DCDCRingSeed's to a DCDCRingSeed in the next ring
710  Link_RingSeeds(myparent, ring, ringend, locSuperLayer, 0);
711  seed_extended = true;
712  }
713  }
714  if((!seed_extended) && (locNumPreviousRingsWithoutHit < MAX_NUM_RINGSEED_RINGS_SKIPABLE))
715  {
716  // no link was found, but try to skip this ring and find a match in the next ring
717  Link_RingSeeds(parent, ring, ringend, locSuperLayer, locNumPreviousRingsWithoutHit + 1);
718  seed_extended = true;
719  }
720  }
721 
722  // Check if this is the end of the line.
723  if(!seed_extended)
724  {
725  // This is the end of this seed.
726  // Check if this seed contains a spiral.
727  int locSpiralRingIndex = -1;
728  for(size_t i = 0; i < parent.size(); ++i)
729  {
730  if(parent[i]->hits.size() < MIN_STRAWS_DEFINITE_SPIRAL_TURN)
731  continue;
732  locSpiralRingIndex = i;
733  break;
734  }
735 
736  // Check whether this seed is an obvious intersection of two tracks (with one of them a spiral)
737  bool locSeparateSeedsFlag = false;
738  if((locSpiralRingIndex != -1) && (parent.size() > 1))
739  {
740  double locAvgNumHitsInNonSpiralRing = 0.0;
741  for(size_t i = 0; i < parent.size(); ++i)
742  {
743  if(int(i) == locSpiralRingIndex)
744  continue;
745  locAvgNumHitsInNonSpiralRing += parent[i]->hits.size();
746  }
747  locAvgNumHitsInNonSpiralRing /= double(parent.size() - 1);
748  if(locAvgNumHitsInNonSpiralRing < 2)
749  locSeparateSeedsFlag = true;
750  }
751 
752  //if obvious intersection: save spiral ring-seed separately
753  if(locSeparateSeedsFlag && (parent[locSpiralRingIndex]->hits.size() >= MIN_SEED_HITS))
754  {
755  DCDCSuperLayerSeed* locSuperLayerSeed = Get_Resource_CDCSuperLayerSeed();
756  for(size_t loc_i = 0; loc_i < parent[locSpiralRingIndex]->hits.size(); ++loc_i)
757  parent[locSpiralRingIndex]->hits[loc_i]->flags |= USED;
758  dSuperLayerSeeds[locSuperLayer - 1].push_back(locSuperLayerSeed);
759  locSuperLayerSeed->dCDCRingSeeds.push_back(*(parent[locSpiralRingIndex]));
760  }
761 
762  //save normal seed if enough hits
763  unsigned int locTotalNumHits = 0;
764  for(size_t i = 0; i < parent.size(); ++i)
765  {
766  if((int(i) == locSpiralRingIndex) && locSeparateSeedsFlag)
767  continue;
768  locTotalNumHits += parent[i]->hits.size();
769  }
770  if(locTotalNumHits < MIN_SEED_HITS)
771  {
772  if(DEBUG_LEVEL > 10)
773  cout << "rejecting seed due to too few hits (have " << locTotalNumHits << " need " << MIN_SEED_HITS << ")" << endl;
774  return;
775  }
776 
777  DCDCSuperLayerSeed* locSuperLayerSeed = Get_Resource_CDCSuperLayerSeed();
778  for(size_t i = 0; i < parent.size(); ++i)
779  {
780  if((int(i) == locSpiralRingIndex) && locSeparateSeedsFlag)
781  continue;
782  locSuperLayerSeed->dCDCRingSeeds.insert(locSuperLayerSeed->dCDCRingSeeds.begin(), *(parent[i])); //input rings were in reverse order!!
783  for(size_t loc_j = 0; loc_j < parent[i]->hits.size(); ++loc_j)
784  parent[i]->hits[loc_j]->flags |= USED;
785  }
786  dSuperLayerSeeds[locSuperLayer - 1].push_back(locSuperLayerSeed);
787  }
788 }
789 
790 //---------
791 // MinDist2
792 //---------
793 double DTrackCandidate_factory_CDC::MinDist2(const DCDCRingSeed& locInnerRingSeed, const DCDCRingSeed& locOuterRingSeed)
794 {
795  const vector<DCDCTrkHit*>& locInnerSeedHits = locInnerRingSeed.hits;
796  const vector<DCDCTrkHit*>& locOuterSeedHits = locOuterRingSeed.hits;
797  return MinDist2(locInnerSeedHits, locOuterSeedHits);
798 }
799 
800 //---------
801 // MinDist2
802 //---------
803 double DTrackCandidate_factory_CDC::MinDist2(const vector<DCDCTrkHit*>& locInnerSeedHits, const vector<DCDCTrkHit*>& locOuterSeedHits)
804 {
805  /// Returns the minimum distance squared between the two seeds. Assumes all of the hits in a given set are on the same ring.
806  /// First it checks if the two seeds overlap in phi: if so, then the radial difference between the rings (squared) is returned.
807  /// Otherwise, only the first and last hits of the adjacent rings between each seed's hit list are used.
808  /// to calculate a maximum of 4 distances (minimum of 1), of which the smallest is returned.
809  if(locInnerSeedHits.empty() || locOuterSeedHits.empty())
810  {
811  cout << "Number of seed hits 0! (Ninner = " << locInnerSeedHits.size() << " ,Nouter = " << locOuterSeedHits.size() << ")" << endl;
812  return 1.0E10;
813  }
814 
815  DCDCTrkHit* locInnermostRingFirstStrawHit = locInnerSeedHits.front();
816  DCDCTrkHit* locInnermostRingLastStrawHit = locInnerSeedHits.back();
817  DCDCTrkHit* locOutermostRingFirstStrawHit = locOuterSeedHits.front();
818  DCDCTrkHit* locOutermostRingLastStrawHit = locOuterSeedHits.back();
819 
820  //see if seeds overlap in phi
821  float locInnermostRingFirstStrawPhi = locInnermostRingFirstStrawHit->hit->wire->phi;
822  float locInnermostRingLastStrawPhi = locInnermostRingLastStrawHit->hit->wire->phi;
823  float locOutermostRingFirstStrawPhi = locOutermostRingFirstStrawHit->hit->wire->phi;
824  float locOutermostRingLastStrawPhi = locOutermostRingLastStrawHit->hit->wire->phi;
825  if(DEBUG_LEVEL > 100)
826  cout << "inner ring: ring, first/last straws & phis = " << locInnermostRingFirstStrawHit->hit->wire->ring << ", " << locInnermostRingFirstStrawHit->hit->wire->straw << ", " << locInnermostRingLastStrawHit->hit->wire->straw << ", " << locInnermostRingFirstStrawPhi << ", " << locInnermostRingLastStrawPhi << endl;
827  if(DEBUG_LEVEL > 100)
828  cout << "outer ring: ring, first/last straws & phis = " << locOutermostRingFirstStrawHit->hit->wire->ring << ", " << locOutermostRingFirstStrawHit->hit->wire->straw << ", " << locOutermostRingLastStrawHit->hit->wire->straw << ", " << locOutermostRingFirstStrawPhi << ", " << locOutermostRingLastStrawPhi << endl;
829 
830  //account for phi = 0/2pi boundary
831  bool locInnerRingCrossesBoundaryFlag = (locInnermostRingLastStrawPhi < locInnermostRingFirstStrawPhi);
832  bool locOuterRingCrossesBoundaryFlag = (locOutermostRingLastStrawPhi < locOutermostRingFirstStrawPhi);
833  if(DEBUG_LEVEL > 100)
834  cout << "in/out boundary flags = " << locInnerRingCrossesBoundaryFlag << ", " << locOuterRingCrossesBoundaryFlag << endl;
835  if(locOuterRingCrossesBoundaryFlag)
836  locOutermostRingLastStrawPhi += M_TWO_PI;
837  if(locInnerRingCrossesBoundaryFlag)
838  locInnermostRingLastStrawPhi += M_TWO_PI;
839  if(locOuterRingCrossesBoundaryFlag & (!locInnerRingCrossesBoundaryFlag) && ((locOutermostRingLastStrawPhi - locInnermostRingLastStrawPhi) > M_PI))
840  {
841  locInnermostRingFirstStrawPhi += M_TWO_PI;
842  locInnermostRingLastStrawPhi += M_TWO_PI;
843  }
844  if(locInnerRingCrossesBoundaryFlag & (!locOuterRingCrossesBoundaryFlag) && ((locInnermostRingLastStrawPhi - locOutermostRingLastStrawPhi) > M_PI))
845  {
846  locOutermostRingFirstStrawPhi += M_TWO_PI;
847  locOutermostRingLastStrawPhi += M_TWO_PI;
848  }
849 
850  if(DEBUG_LEVEL > 100)
851  cout << "final inner ring: ring, first/last straws & phis = " << locInnermostRingFirstStrawHit->hit->wire->ring << ", " << locInnermostRingFirstStrawHit->hit->wire->straw << ", " << locInnermostRingLastStrawHit->hit->wire->straw << ", " << locInnermostRingFirstStrawPhi << ", " << locInnermostRingLastStrawPhi << endl;
852  if(DEBUG_LEVEL > 100)
853  cout << "final outer ring: ring, first/last straws & phis = " << locOutermostRingFirstStrawHit->hit->wire->ring << ", " << locOutermostRingFirstStrawHit->hit->wire->straw << ", " << locOutermostRingLastStrawHit->hit->wire->straw << ", " << locOutermostRingFirstStrawPhi << ", " << locOutermostRingLastStrawPhi << endl;
854 
855  //finally check for overlaps
856  double dr = locOutermostRingLastStrawHit->hit->wire->origin.Perp() - locInnermostRingFirstStrawHit->hit->wire->origin.Perp();
857  if((locOutermostRingFirstStrawPhi >= locInnermostRingFirstStrawPhi) && (locOutermostRingFirstStrawPhi <= locInnermostRingLastStrawPhi))
858  return dr*dr;
859  if((locOutermostRingLastStrawPhi >= locInnermostRingFirstStrawPhi) && (locOutermostRingLastStrawPhi <= locInnermostRingLastStrawPhi))
860  return dr*dr;
861  if((locInnermostRingFirstStrawPhi >= locOutermostRingFirstStrawPhi) && (locInnermostRingFirstStrawPhi <= locOutermostRingLastStrawPhi))
862  return dr*dr; //4th case not needed. this case only needed if innermost ring is one wire across
863 
864  //no overlap, make all 4 comparisons between hits
865  double d2, d2min;
866  d2min = locInnermostRingFirstStrawHit->Dist2(locOutermostRingFirstStrawHit);
867  if(locOutermostRingFirstStrawHit != locOutermostRingLastStrawHit)
868  {
869  d2 = locInnermostRingFirstStrawHit->Dist2(locOutermostRingLastStrawHit);
870  if(d2 < d2min)
871  d2min = d2;
872  }
873  if(locInnermostRingFirstStrawHit == locInnermostRingLastStrawHit)
874  return d2min;
875 
876  d2 = locInnermostRingLastStrawHit->Dist2(locOutermostRingFirstStrawHit);
877  if(d2 < d2min)
878  d2min = d2;
879  if(locOutermostRingFirstStrawHit != locOutermostRingLastStrawHit)
880  {
881  d2 = locInnermostRingLastStrawHit->Dist2(locOutermostRingLastStrawHit);
882  if(d2 < d2min)
883  d2min = d2;
884  }
885 
886  return d2min;
887 }
888 
889 //---------------------------------------
890 // Reject_SuperLayerSeeds_HighSeedDensity
891 //---------------------------------------
893 {
894  //The track finding algorithm will grind to a halt if there are too many super layer seeds in a given area
895  //e.g. A slow spiral pion that loses energy very slowly will loop around many, many times before stopping,
896  //sometimes resulting in 40+ super layer seeds in a given super layer.
897  //Therefore, if the density of super layer seeds in a given region is too high, reject all super layer seeds passing through that region of space, except for the ones on the edges
898  //It will be impossible to determine track parameters in these regions anyway, so may as well reject them.
899 
900  if(SEED_DENSITY_BIN_STRAW_WIDTH == 0)
901  return; //rejection disabled
902 
903  vector<DCDCSuperLayerSeed*>& locSuperLayerSeeds = dSuperLayerSeeds[locSuperLayer - 1];
904  if(locSuperLayerSeeds.size() <= MAX_SEEDS_IN_STRAW_BIN)
905  return; //not enough for there to even possibly be an issue
906 
907  // histogram phis of all seeds within this super layer
908  // We use a simple array to store our histogram here. We don't want to use ROOT histograms because they are not thread safe.
909  // Setup histogram
910  unsigned int hist[dNumSeedDensityPhiBins];
911  for(unsigned int i = 0; i < dNumSeedDensityPhiBins; ++i)
912  hist[i] = 0; // clear histogram
913  double bin_width = M_TWO_PI/(double)dNumSeedDensityPhiBins;
914  double hist_low_limit = 0.0; // lower edge of histogram limits
915 
916  //Find phi ranges of super layer seeds: store in map & histogram them
917  map<unsigned int, pair<double, double> > locMapPhiRanges; //key is seed index, pair is phi range (first/last) //first > last if passes through phi = 0 boundary
918  for(size_t loc_i = 0; loc_i < locSuperLayerSeeds.size(); ++loc_i)
919  {
920  double locSeedFirstPhi, locSeedLastPhi;
921  Calc_SuperLayerPhiRange(locSuperLayerSeeds[loc_i], locSeedFirstPhi, locSeedLastPhi);
922  locMapPhiRanges[locSuperLayerSeeds[loc_i]->dSeedIndex] = pair<double, double>(locSeedFirstPhi, locSeedLastPhi);
923  if(DEBUG_LEVEL > 20)
924  cout << "super layer, seed index, first phi, last phi = " << locSuperLayer << ", " << locSuperLayerSeeds[loc_i]->dSeedIndex << ", " << locSeedFirstPhi << ", " << locSeedLastPhi << endl;
925 
926  unsigned int locFirstPhiBin = (unsigned int)((locSeedFirstPhi - hist_low_limit)/bin_width);
927  unsigned int locLastPhiBin = (unsigned int)((locSeedLastPhi - hist_low_limit)/bin_width);
928  for(unsigned int locPhiBin = locFirstPhiBin; locPhiBin <= locLastPhiBin; ++locPhiBin)
929  ++hist[locPhiBin];
930  }
931 
932  //determine search window size:
933  unsigned int locOuterRing = superlayer_boundaries[locSuperLayer - 1];
934  unsigned int locAverageNumStrawsInRing = (dNumStrawsPerRing[locOuterRing - 4] + dNumStrawsPerRing[locOuterRing - 1])/2; //I know it floored; it's close enough
935  double locSearchBinPhiSize = double(SEED_DENSITY_BIN_STRAW_WIDTH)*M_TWO_PI/double(locAverageNumStrawsInRing);
936 
937  //find the search start point: try to start somewhere where there are no seeds for a range that is at least as large as the window; else start at 0
938  int locStartPhiBin = -1;
939  for(unsigned int locPhiBin = 0; locPhiBin < dNumSeedDensityPhiBins; ++locPhiBin)
940  {
941  if(hist[locPhiBin] > 0)
942  {
943  locStartPhiBin = -1;
944  continue;
945  }
946  if(locStartPhiBin == -1)
947  locStartPhiBin = locPhiBin;
948  else if((locPhiBin - locStartPhiBin) > locSearchBinPhiSize)
949  break;
950  }
951  if(locStartPhiBin == -1)
952  locStartPhiBin = 0;
953 
954  // loop over phi range, scanning with a window of size "locSearchBinPhiSize," finding where the density of seeds is too high and marking those seeds for rejection
955  set<unsigned int> locSeedsToReject;
956  for(unsigned int locPhiBin = 0; locPhiBin < dNumSeedDensityPhiBins; ++locPhiBin)
957  {
958  unsigned int locReadPhiBin = locStartPhiBin + locPhiBin;
959  if(locReadPhiBin >= dNumSeedDensityPhiBins)
960  locReadPhiBin -= dNumSeedDensityPhiBins;
961 
962  double locWindowPhiRangeMin = hist_low_limit + bin_width*(double(locReadPhiBin));
963  if(locWindowPhiRangeMin >= M_TWO_PI)
964  locWindowPhiRangeMin -= M_TWO_PI;
965  double locWindowPhiRangeMax = locWindowPhiRangeMin + locSearchBinPhiSize;
966 
967  map<unsigned int, pair<double, double> >::const_iterator locSeedIterator = locMapPhiRanges.begin();
968  vector<unsigned int> locSeedsInThisRange;
969  for(; locSeedIterator != locMapPhiRanges.end(); ++locSeedIterator)
970  {
971  double locSeedPhiRangeMin = locSeedIterator->second.first;
972  double locSeedPhiRangeMax = locSeedIterator->second.second;
973  if(Check_IfPhiRangesOverlap(locSeedPhiRangeMin, locSeedPhiRangeMax, locWindowPhiRangeMin, locWindowPhiRangeMax))
974  locSeedsInThisRange.push_back(locSeedIterator->first);
975  }
976  if(locSeedsInThisRange.size() <= MAX_SEEDS_IN_STRAW_BIN)
977  continue;
978 
979  //mark these seeds for deletion
980  for(size_t loc_i = 0; loc_i < locSeedsInThisRange.size(); ++loc_i)
981  locSeedsToReject.insert(locSeedsInThisRange[loc_i]);
982  }
983 
984  //loop over seeds marked for rejection: keep the first and last seeds of each group
985  //ignore phi = 0 barrier for now
986  //also, mark phi regions as bad
987  set<unsigned int>::const_iterator locRejectIterator = locSeedsToReject.begin();
988  int locBeginIndex = -1, locPreviousIndex = 0, locFirstIndex = 0, locEndIndex = 0;
989  set<unsigned int> locSeedsToNotReject;
990  for(; locRejectIterator != locSeedsToReject.end(); ++locRejectIterator)
991  {
992  unsigned int locCurrentIndex = *locRejectIterator;
993  if(DEBUG_LEVEL > 15)
994  cout << "Marked for rejection: super layer, seed index = " << locSuperLayer << ", " << locCurrentIndex << endl;
995  if(locBeginIndex == -1)
996  {
997  locFirstIndex = locCurrentIndex;
998  locBeginIndex = locCurrentIndex;
999  locSeedsToNotReject.insert(locBeginIndex);
1000  if(DEBUG_LEVEL > 15)
1001  cout << "don't reject: " << locBeginIndex << endl;
1002  }
1003  if(DEBUG_LEVEL > 30)
1004  cout << "window size, current phis, previous phis = " << locSearchBinPhiSize << ", " << locMapPhiRanges[locCurrentIndex].first << ", " << locMapPhiRanges[locCurrentIndex].second << ", " << locMapPhiRanges[locPreviousIndex].first << ", " << locMapPhiRanges[locPreviousIndex].second << endl;
1005  if(Check_IfPhiRangesOverlap(locMapPhiRanges[locCurrentIndex].first, locMapPhiRanges[locCurrentIndex].second, locMapPhiRanges[locPreviousIndex].first, locMapPhiRanges[locPreviousIndex].second + locSearchBinPhiSize))
1006  {
1007  locPreviousIndex = locCurrentIndex;
1008  locEndIndex = locCurrentIndex;
1009  continue;
1010  }
1011  if(Check_IfPhiRangesOverlap(locMapPhiRanges[locCurrentIndex].first, locMapPhiRanges[locCurrentIndex].second, locMapPhiRanges[locPreviousIndex].first - locSearchBinPhiSize, locMapPhiRanges[locPreviousIndex].second))
1012  {
1013  locPreviousIndex = locCurrentIndex;
1014  locEndIndex = locCurrentIndex;
1015  continue;
1016  }
1017 
1018  //seed isn't within locSearchBinPhiSize of previous seed: edge
1019  if(DEBUG_LEVEL > 15)
1020  cout << "Unmark for rejection: super layer, seed indexes = " << locSuperLayer << ", " << locBeginIndex << ", " << locPreviousIndex << endl;
1021 
1022  //too many seeds in this region: in future super layers, don't assume unmatched seeds in this region are new tracks
1023  dRejectedPhiRegions[locSuperLayer - 1].push_back(pair<double, double>(locMapPhiRanges[locBeginIndex].first, locMapPhiRanges[locPreviousIndex].second));
1024 
1025  locSeedsToNotReject.insert(locPreviousIndex);
1026  locSeedsToNotReject.insert(locCurrentIndex); //beginning of new section
1027  locBeginIndex = locCurrentIndex;
1028  locPreviousIndex = locCurrentIndex;
1029  locEndIndex = locCurrentIndex;
1030  }
1031  locSeedsToNotReject.insert(locEndIndex); //don't reject the last one //will check overlap below
1032 
1033  if(DEBUG_LEVEL > 30)
1034  cout << "first phis, last phis = " << locMapPhiRanges[locFirstIndex].first << ", " << locMapPhiRanges[locFirstIndex].second << ", " << locMapPhiRanges[locEndIndex].first << ", " << locMapPhiRanges[locEndIndex].second << endl;
1035 
1036  //check to see if last overlaps with first //overlap across phi = 0 barrier
1037  if(Check_IfPhiRangesOverlap(locMapPhiRanges[locFirstIndex].first, locMapPhiRanges[locFirstIndex].second, locMapPhiRanges[locEndIndex].first, locMapPhiRanges[locEndIndex].second))
1038  {
1039  if(DEBUG_LEVEL > 15)
1040  cout << "re-reject first/last = " << locFirstIndex << ", " << locEndIndex << endl;
1041  //do reject them
1042  locSeedsToNotReject.erase(locFirstIndex);
1043  locSeedsToNotReject.erase(locEndIndex);
1044  }
1045 
1046 
1047  // reject (and recycle) the seeds in areas where the seeds were too dense
1048  for(vector<DCDCSuperLayerSeed*>::iterator locvectorIterator = locSuperLayerSeeds.begin(); locvectorIterator != locSuperLayerSeeds.end();)
1049  {
1050  unsigned int locSeedIndex = (*locvectorIterator)->dSeedIndex;
1051  if((locSeedsToReject.find(locSeedIndex) != locSeedsToReject.end()) && (locSeedsToNotReject.find(locSeedIndex) == locSeedsToNotReject.end()))
1052  {
1053  if(DEBUG_LEVEL > 10)
1054  cout << "seed density too high, reject seed: " << locSeedIndex << endl;
1055  dCDCSuperLayerSeedPool_Available.push_back(*locvectorIterator); //recycle memory
1056  locvectorIterator = locSuperLayerSeeds.erase(locvectorIterator);
1057  }
1058  else
1059  ++locvectorIterator;
1060  }
1061 }
1062 
1063 //------------------------
1064 // Calc_SuperLayerPhiRange
1065 //------------------------
1066 void DTrackCandidate_factory_CDC::Calc_SuperLayerPhiRange(DCDCSuperLayerSeed* locSuperLayerSeed, double& locSeedFirstPhi, double& locSeedLastPhi)
1067 {
1068  // Calculate the phi-range across which the DCDCSuperLayerSeed extends.
1069  locSeedFirstPhi = 9.9E9;
1070  locSeedLastPhi = -9.9E9;
1071  for(size_t loc_j = 0; loc_j < locSuperLayerSeed->dCDCRingSeeds.size(); ++loc_j)
1072  {
1073  if (locSuperLayerSeed->dCDCRingSeeds[loc_j].hits.empty()) continue;
1074  DCDCTrkHit *locFirstStrawHit = locSuperLayerSeed->dCDCRingSeeds[loc_j].hits.front();
1075  DCDCTrkHit *locLastStrawHit = locSuperLayerSeed->dCDCRingSeeds[loc_j].hits.back();
1076 
1077  double locRingFirstPhi = locFirstStrawHit->hit->wire->phi;
1078  if(locRingFirstPhi < 0.0)
1079  locRingFirstPhi += M_TWO_PI;
1080  double locRingLastPhi = locLastStrawHit->hit->wire->phi;
1081  if(locRingLastPhi < 0.0)
1082  locRingLastPhi += M_TWO_PI;
1083  if(loc_j == 0)
1084  {
1085  locSeedFirstPhi = locRingFirstPhi;
1086  locSeedLastPhi = locRingLastPhi;
1087  continue;
1088  }
1089 
1090  if(locSeedFirstPhi > locSeedLastPhi) //seed goes across phi = 0 boundary
1091  {
1092  if(locRingFirstPhi > locRingLastPhi) //ring goes across phi = 0 boundary
1093  {
1094  if(locRingFirstPhi < locSeedFirstPhi)
1095  locSeedFirstPhi = locRingFirstPhi;
1096  if(locRingLastPhi > locSeedLastPhi)
1097  locSeedLastPhi = locRingLastPhi;
1098  }
1099  else
1100  {
1101  if((locRingFirstPhi > M_PI) && (locRingFirstPhi < locSeedFirstPhi))
1102  locSeedFirstPhi = locRingFirstPhi;
1103  else if((locRingLastPhi < M_PI) && (locRingLastPhi > locSeedLastPhi))
1104  locSeedLastPhi = locRingLastPhi;
1105  }
1106  }
1107  else //seed does not (so far) go across phi = 0 boundary
1108  {
1109  if(locRingFirstPhi > locRingLastPhi) //ring goes across phi = 0 boundary
1110  {
1111  locSeedFirstPhi = locRingFirstPhi;
1112  if(locRingLastPhi > locSeedLastPhi)
1113  locSeedLastPhi = locRingLastPhi;
1114  }
1115  else
1116  {
1117  if(locRingFirstPhi < locSeedFirstPhi)
1118  locSeedFirstPhi = locRingFirstPhi;
1119  if(locRingLastPhi > locSeedLastPhi)
1120  locSeedLastPhi = locRingLastPhi;
1121  }
1122  }
1123  }
1124 }
1125 
1126 //-------------------------
1127 // Check_IfPhiRangesOverlap
1128 //-------------------------
1129 bool DTrackCandidate_factory_CDC::Check_IfPhiRangesOverlap(double locFirstSeedPhi, double locLastSeedPhi, double locTargetFirstPhi, double locTargetLastPhi)
1130 {
1131  //if first phi > last phi 2nd, then it extends through the phi = 0 boundary
1132  if(locFirstSeedPhi > locLastSeedPhi) //seed extends through phi = 0 boundary
1133  {
1134  if(locTargetFirstPhi > locTargetLastPhi) //hist range extends through phi = 0 boundary
1135  return true; //clearly both intersect: both cross phi = 0
1136  else
1137  {
1138 //S: F---|---L
1139 //H: FXXXL | FXXXL
1140  if(locTargetLastPhi > locFirstSeedPhi)
1141  return true;
1142  else if(locTargetFirstPhi < locLastSeedPhi)
1143  return true;
1144  }
1145  }
1146  else //seed does not extend through phi = 0 boundary
1147  {
1148  if(locTargetFirstPhi > locTargetLastPhi) //hist range extends through phi = 0 boundary
1149  {
1150 //H: F---|---L
1151 //S: FXXXL | FXXXL
1152  if(locLastSeedPhi > locTargetFirstPhi)
1153  return true;
1154  else if(locFirstSeedPhi < locTargetLastPhi)
1155  return true;
1156  }
1157  else
1158  {
1159  if((locTargetFirstPhi > locFirstSeedPhi) && (locTargetFirstPhi < locLastSeedPhi))
1160  return true;
1161  else if((locTargetLastPhi > locFirstSeedPhi) && (locTargetLastPhi < locLastSeedPhi))
1162  return true;
1163  else if((locFirstSeedPhi > locTargetFirstPhi) && (locFirstSeedPhi < locTargetLastPhi))
1164  return true;
1165  }
1166  }
1167  return false;
1168 }
1169 
1170 /*********************************************************************************************************************************************************************/
1171 /********************************************************************** SEARCH FOR SPIRAL LINKS **********************************************************************/
1172 /*********************************************************************************************************************************************************************/
1173 
1174 //---------------------
1175 // Set_SpiralLinkParams
1176 //---------------------
1178 {
1179  // Search for Spiral Links within and between super layer seeds
1180  //don't worry about getting every case: it's better to have extra particles reconstructed than to be overzealous and lose some!!
1181  for(size_t loc_i = 0; loc_i < dSuperLayerSeeds.size(); ++loc_i)
1182  {
1183  vector<DCDCSuperLayerSeed*>& locSuperLayerSeeds = dSuperLayerSeeds[loc_i];
1184  for(size_t loc_j = 0; loc_j < locSuperLayerSeeds.size(); ++loc_j)
1185  {
1186  for(size_t loc_k = loc_j + 1; loc_k < locSuperLayerSeeds.size(); ++loc_k)
1187  {
1188  if(SearchFor_SpiralTurn_TwoSeedsSharingManyHits(locSuperLayerSeeds[loc_j], locSuperLayerSeeds[loc_k]))
1189  continue;
1190  if(SearchFor_SpiralTurn_TwoSeedsSharingFewHits(locSuperLayerSeeds[loc_j], locSuperLayerSeeds[loc_k]))
1191  continue;
1192  if(SearchFor_SpiralTurn_MissingOrBetweenRings(locSuperLayerSeeds[loc_j], locSuperLayerSeeds[loc_k]))
1193  continue;
1194  }
1195  // if this super layer seed has not yet been linked to any other seed, check to see if itself is the spiral turn
1196  // e.g. only (and many) hits in one ring of super-layer 7.
1197  if(locSuperLayerSeeds[loc_j]->dSpiralLinkParams.empty()) //empty if not identified as a spiral yet
1198  SearchFor_SpiralTurn_SingleSeed(locSuperLayerSeeds[loc_j]);
1199  }
1200  }
1201 }
1202 
1203 //---------------------------------------------
1204 // SearchFor_SpiralTurn_TwoSeedsSharingManyHits
1205 //---------------------------------------------
1207 {
1208  //check if two seeds share at least MIN_STRAWS_POTENTIAL_SPIRAL_TURN on the same ring
1209 
1210  int locMaxSpiralNumHits = 0; //can have more than one potential spiral turn on a seed: could have two tracks (or two spiral arms) turning near each other
1211  //search all rings: spiral turn may not be on outermost ring if two tracks are crossing
1212  for(size_t loc_i = 0; loc_i < locSuperLayerSeed1->dCDCRingSeeds.size(); ++loc_i)
1213  {
1214  int locRing = locSuperLayerSeed1->dCDCRingSeeds[loc_i].ring;
1215  if(!locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locRing))
1216  continue; //the hits on this ring aren't the same in both DCDCSuperLayerSeed's
1217  int locLocalRingNumber = (locRing - 1)%4 + 1; //ranges from 1 -> 4 //ring of super layer
1218 
1219  // find how many straws are in this ring
1220  int locNumHits = locSuperLayerSeed1->dCDCRingSeeds[loc_i].hits.size();
1221  if(locNumHits < locMaxSpiralNumHits)
1222  continue; //already found a potential spiral link in this seed with a > # of straws
1223 
1224  if(locNumHits >= int(MIN_STRAWS_POTENTIAL_SPIRAL_TURN))
1225  {
1226  // check to make sure the hits on the first and last rings (in this super layer) of both DCDCSuperLayerSeed's aren't identical
1227  //if so, then if there truly is a spiral, this is the wrong combination of DCDCSuperLayerSeed's for it
1228  int locFirstRing1 = locSuperLayerSeed1->dCDCRingSeeds.front().ring;
1229  int locFirstRing2 = locSuperLayerSeed2->dCDCRingSeeds.front().ring;
1230  int locLastRing1 = locSuperLayerSeed1->dCDCRingSeeds.back().ring;
1231  int locLastRing2 = locSuperLayerSeed2->dCDCRingSeeds.back().ring;
1232  if((locFirstRing1 == locFirstRing2) && (locLastRing1 == locLastRing2))
1233  {
1234  if(locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locFirstRing1) && locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locLastRing1))
1235  continue;
1236  }
1237 
1238  int locTempSpiralNumHits = 0;
1239  if((locLocalRingNumber != 1) && (locLocalRingNumber != 4))
1240  {
1241  //spiral turn is not on an edge ring, it is on one of the two middle rings instead: there must also be MIN_STRAWS_ADJACENT_TO_SPIRAL_TURN hits in an adjacent ring
1242  //if spiral turn was on an edge ring, there may be many hits in the adjacent ring that is in another super layer, so can't do this check
1243  if(!SearchFor_SpiralTurn_ManyHitsAdjacentRing(locSuperLayerSeed1, locSuperLayerSeed2, locRing + 1, MIN_STRAWS_ADJACENT_TO_SPIRAL_TURN, locTempSpiralNumHits))
1244  {
1245  if(!SearchFor_SpiralTurn_ManyHitsAdjacentRing(locSuperLayerSeed1, locSuperLayerSeed2, locRing - 1, MIN_STRAWS_ADJACENT_TO_SPIRAL_TURN, locTempSpiralNumHits))
1246  continue; //not a spiral turn: there was only a few straws on the adjacent rings //perhaps this was two nearby tracks instead
1247  }
1248  }
1249 
1250  // is potential spiral turn, save results
1251  locMaxSpiralNumHits = locNumHits;
1252  DSpiralParams_t locSpiralTurnParams;
1253  //try to determine whether the track is turning inwards or outwards in this ring
1254  int locSpiralTurnRingFlag = 0;
1255  if(locSuperLayerSeed1->dCDCRingSeeds.size() == 1)
1256  locSpiralTurnRingFlag = ((locRing - 1)%4 > 1) ? 1 : -1;
1257  else if(loc_i == 0)
1258  locSpiralTurnRingFlag = -1; //turn on innermost ring
1259  else if(loc_i == (locSuperLayerSeed1->dCDCRingSeeds.size() - 1))
1260  locSpiralTurnRingFlag = 1; //turn on outermost ring
1261  else if(locSuperLayerSeed1->dCDCRingSeeds[loc_i + 1].hits.size() > locSuperLayerSeed1->dCDCRingSeeds[loc_i - 1].hits.size())
1262  locSpiralTurnRingFlag = -1; //more hits on outer ring than inner ring: turn on innermost ring
1263  else
1264  locSpiralTurnRingFlag = 1; //turn on outermost ring (if hit vector sizes are equal, assume outermost)
1265  locSpiralTurnParams.dSpiralTurnRingFlag = locSpiralTurnRingFlag;
1266  locSpiralTurnParams.dSpiralTurnRing = locRing;
1267  locSpiralTurnParams.dDefiniteSpiralTurnRingFlag = (locNumHits >= int(MIN_STRAWS_DEFINITE_SPIRAL_TURN)) ? locSpiralTurnRingFlag : 0;
1268  locSuperLayerSeed1->dSpiralLinkParams[locSuperLayerSeed2->dSeedIndex] = locSpiralTurnParams;
1269  locSuperLayerSeed2->dSpiralLinkParams[locSuperLayerSeed1->dSeedIndex] = locSpiralTurnParams;
1270  if(DEBUG_LEVEL > 10)
1271  cout << "SL" << locSuperLayerSeed1->dSuperLayer << " Seed" << locSuperLayerSeed1->dSeedIndex << " Spiral-linked to SL" << locSuperLayerSeed2->dSuperLayer << " Seed" << locSuperLayerSeed2->dSeedIndex << ": Share Many Hits, Ring = " << locRing << endl;
1272  }
1273  }
1274  return (locMaxSpiralNumHits > 0);
1275 }
1276 
1277 //--------------------------------------------
1278 // SearchFor_SpiralTurn_TwoSeedsSharingFewHits
1279 //--------------------------------------------
1281 {
1282  // check if: two seeds share a few hits on a given ring, and at least one has very many (unshared) hits on an adjacent ring: spiral turn
1283 
1284  int locMaxSpiralNumHits = 0; //can have more than one potential spiral turn on a seed: could have two tracks (or two spiral arms) turning near each other
1285  for(size_t loc_i = 0; loc_i < locSuperLayerSeed1->dCDCRingSeeds.size(); ++loc_i)
1286  {
1287  int locRing = locSuperLayerSeed1->dCDCRingSeeds[loc_i].ring;
1288  if(!locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locRing))
1289  continue;
1290 
1291  //check locRing - 1 for many hits: check if track is turning back inwards
1292  int locTempSpiralNumHits = -2;
1293  if(SearchFor_SpiralTurn_ManyHitsAdjacentRing(locSuperLayerSeed1, locSuperLayerSeed2, locRing - 1, MIN_STRAWS_POTENTIAL_SPIRAL_TURN, locTempSpiralNumHits))
1294  {
1295  //is potential spiral turn
1296  if(locTempSpiralNumHits > locMaxSpiralNumHits)
1297  {
1298  locMaxSpiralNumHits = locTempSpiralNumHits;
1299  DSpiralParams_t locSpiralTurnParams;
1300  int locSpiralTurnRingFlag = 1; //turning inwards
1301  locSpiralTurnParams.dSpiralTurnRingFlag = locSpiralTurnRingFlag;
1302  locSpiralTurnParams.dSpiralTurnRing = locRing;
1303  bool locIsDefiniteSpiralTurn = (locTempSpiralNumHits > int(MIN_STRAWS_DEFINITE_SPIRAL_TURN));
1304  locSpiralTurnParams.dDefiniteSpiralTurnRingFlag = locIsDefiniteSpiralTurn ? locSpiralTurnRingFlag : 0;
1305  locSuperLayerSeed1->dSpiralLinkParams[locSuperLayerSeed2->dSeedIndex] = locSpiralTurnParams;
1306  locSuperLayerSeed2->dSpiralLinkParams[locSuperLayerSeed1->dSeedIndex] = locSpiralTurnParams;
1307  if(DEBUG_LEVEL > 10)
1308  cout << "SL" << locSuperLayerSeed1->dSuperLayer << " Seed" << locSuperLayerSeed1->dSeedIndex << " Spiral-linked to SL" << locSuperLayerSeed2->dSuperLayer << " Seed" << locSuperLayerSeed2->dSeedIndex << ": Share Few Hits, Ring = " << locRing << endl;
1309  }
1310  }
1311 
1312  //check locRing + 1 for many hits: check if track is turning back outwards
1313  locTempSpiralNumHits = -2;
1314  if(SearchFor_SpiralTurn_ManyHitsAdjacentRing(locSuperLayerSeed1, locSuperLayerSeed2, locRing + 1, MIN_STRAWS_POTENTIAL_SPIRAL_TURN, locTempSpiralNumHits))
1315  {
1316  //is potential spiral turn
1317  if(locTempSpiralNumHits > locMaxSpiralNumHits)
1318  {
1319  locMaxSpiralNumHits = locTempSpiralNumHits;
1320  DSpiralParams_t locSpiralTurnParams;
1321  int locSpiralTurnRingFlag = -1; //turning outwards
1322  locSpiralTurnParams.dSpiralTurnRingFlag = locSpiralTurnRingFlag;
1323  locSpiralTurnParams.dSpiralTurnRing = locRing;
1324  bool locIsDefiniteSpiralTurn = (locTempSpiralNumHits > int(MIN_STRAWS_DEFINITE_SPIRAL_TURN));
1325  locSpiralTurnParams.dDefiniteSpiralTurnRingFlag = locIsDefiniteSpiralTurn ? locSpiralTurnRingFlag : 0;
1326  locSuperLayerSeed1->dSpiralLinkParams[locSuperLayerSeed2->dSeedIndex] = locSpiralTurnParams;
1327  locSuperLayerSeed2->dSpiralLinkParams[locSuperLayerSeed1->dSeedIndex] = locSpiralTurnParams;
1328  if(DEBUG_LEVEL > 10)
1329  cout << "SL" << locSuperLayerSeed1->dSuperLayer << " Seed" << locSuperLayerSeed1->dSeedIndex << " Spiral-linked to SL" << locSuperLayerSeed2->dSuperLayer << " Seed" << locSuperLayerSeed2->dSeedIndex << ": Share Few Hits, Ring = " << locRing << endl;
1330  }
1331  }
1332  }
1333 
1334  return (locMaxSpiralNumHits > 0);
1335 }
1336 
1337 //------------------------------------------
1338 // SearchFor_SpiralTurn_ManyHitsAdjacentRing
1339 //------------------------------------------
1340 bool DTrackCandidate_factory_CDC::SearchFor_SpiralTurn_ManyHitsAdjacentRing(DCDCSuperLayerSeed* locSuperLayerSeed1, DCDCSuperLayerSeed* locSuperLayerSeed2, int locRingToCheck, int locMinStrawsAdjacentRing, int& locMaxSpiralNumHits)
1341 {
1342  //utility function, used to confirm if there are many hits on both seeds in the given ring
1343  if(locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locRingToCheck))
1344  return false; //these hits are the same
1345 
1346  vector<DCDCTrkHit*> locHits1;
1347  for(size_t loc_i = 0; loc_i < locSuperLayerSeed1->dCDCRingSeeds.size(); ++loc_i)
1348  {
1349  if(locSuperLayerSeed1->dCDCRingSeeds[loc_i].ring != locRingToCheck)
1350  continue;
1351  locHits1 = locSuperLayerSeed1->dCDCRingSeeds[loc_i].hits;
1352  break;
1353  }
1354  if(locHits1.empty())
1355  return false;
1356 
1357  vector<DCDCTrkHit*> locHits2;
1358  for(size_t loc_j = 0; loc_j < locSuperLayerSeed2->dCDCRingSeeds.size(); ++loc_j)
1359  {
1360  if(locSuperLayerSeed2->dCDCRingSeeds[loc_j].ring != locRingToCheck)
1361  continue;
1362  locHits2 = locSuperLayerSeed2->dCDCRingSeeds[loc_j].hits;
1363  break;
1364  }
1365  if(locHits2.empty())
1366  return false;
1367 
1368  int locNumHits1 = locHits1.size();
1369  int locNumHits2 = locHits2.size();
1370 
1371  if((locNumHits1 < int(locMinStrawsAdjacentRing)) || (locNumHits2 < int(locMinStrawsAdjacentRing)))
1372  return false; //neither seed has enough hits on the adjacent ring: return false
1373 
1374  // check to make sure the hits on the inner & outer rings of both seeds aren't identical
1375  //if there truly is a spiral, then this is the wrong combo of seeds for it
1376  int locFirstRing1 = locSuperLayerSeed1->dCDCRingSeeds.front().ring;
1377  int locFirstRing2 = locSuperLayerSeed2->dCDCRingSeeds.front().ring;
1378  int locLastRing1 = locSuperLayerSeed1->dCDCRingSeeds.back().ring;
1379  int locLastRing2 = locSuperLayerSeed2->dCDCRingSeeds.back().ring;
1380  if((locFirstRing1 == locFirstRing2) && (locLastRing1 == locLastRing2))
1381  {
1382  if(locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locFirstRing1) && locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locLastRing1))
1383  return false;
1384  }
1385 
1386  locMaxSpiralNumHits = locNumHits1;
1387  if(locNumHits2 > locMaxSpiralNumHits)
1388  locMaxSpiralNumHits = locNumHits2;
1389 
1390  return true;
1391 }
1392 
1393 //-------------------------------------------
1394 // SearchFor_SpiralTurn_MissingOrBetweenRings
1395 //-------------------------------------------
1397 {
1398  // sometimes the spiral turn occurs between rings (or in a region with a dead high-voltage board). this function attempts to find these
1399  // the signature is that both seeds have many hits in a given ring. these hits must be different but nearby, and the majority of the hits in the other rings must be further away from the other seed
1400  int locMaxSpiralNumHits = 0; //can have more than one potential spiral turn on a seed: could have two tracks (or two spiral arms) turning near each other
1401  for(size_t loc_i = 0; loc_i < locSuperLayerSeed1->dCDCRingSeeds.size(); ++loc_i)
1402  {
1403  int locRing = locSuperLayerSeed1->dCDCRingSeeds[loc_i].ring;
1404 
1405  //make sure there are enough straws on this ring in seed1
1406  vector<DCDCTrkHit*>& locHits1 = locSuperLayerSeed1->dCDCRingSeeds[loc_i].hits;
1407  int locNumHits1 = locHits1.size();
1408  if(locNumHits1 < int(MIN_STRAWS_POTENTIAL_SPIRAL_TURN))
1409  continue; //not enough straws
1410 
1411  for(size_t loc_j = 0; loc_j < locSuperLayerSeed2->dCDCRingSeeds.size(); ++loc_j)
1412  {
1413  if(locSuperLayerSeed2->dCDCRingSeeds[loc_j].ring != locRing)
1414  continue; //select the same ring as in seed1
1415 
1416  vector<DCDCTrkHit*>& locHits2 = locSuperLayerSeed2->dCDCRingSeeds[loc_j].hits;
1417  if(locHits2 == locHits1)
1418  break; //hits are shared: if truly was a spiral, will have been picked up earlier
1419 
1420  //make sure there are enough straws on this ring in seed2
1421  int locNumHits2 = locHits2.size();
1422  if(locNumHits2 < int(MIN_STRAWS_POTENTIAL_SPIRAL_TURN))
1423  break; //not enough straws
1424 
1425  bool locAtLeastOneSeedDefiniteTurnFlag = (locNumHits1 >= int(MIN_STRAWS_DEFINITE_SPIRAL_TURN));
1426  if(locNumHits2 >= int(MIN_STRAWS_DEFINITE_SPIRAL_TURN))
1427  locAtLeastOneSeedDefiniteTurnFlag = true;
1428 
1429  //check to make sure the seeds are nearby
1430  int locStrawNumDiff = abs(locHits2.front()->hit->wire->straw - locHits1.back()->hit->wire->straw);
1431  int locNumStrawsInRing = dNumStrawsPerRing[locRing - 1];
1432  if(locStrawNumDiff > locNumStrawsInRing/2)
1433  locStrawNumDiff = locNumStrawsInRing - locStrawNumDiff; //crosses straw count edge
1434  int locNumHits = locStrawNumDiff - 1;
1435  if(locNumHits > int(MAX_STRAWS_BETWEEN_LINK_SPIRAL_TURN))
1436  break; //straw groups are too far apart
1437 
1438  // check to make sure the hits on the inner & outer rings of both seeds aren't identical
1439  //if there truly is a spiral, then this is the wrong combo of seeds for it
1440  int locFirstRing1 = locSuperLayerSeed1->dCDCRingSeeds.front().ring;
1441  int locFirstRing2 = locSuperLayerSeed2->dCDCRingSeeds.front().ring;
1442  int locLastRing1 = locSuperLayerSeed1->dCDCRingSeeds.back().ring;
1443  int locLastRing2 = locSuperLayerSeed2->dCDCRingSeeds.back().ring;
1444  if((locFirstRing1 == locFirstRing2) && (locLastRing1 == locLastRing2))
1445  {
1446  if(locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locFirstRing1) && locSuperLayerSeed1->Are_AllHitsOnRingShared(locSuperLayerSeed2, locLastRing1))
1447  continue;
1448  }
1449 
1450  if((locNumHits1 < locMaxSpiralNumHits) && (locNumHits2 < locMaxSpiralNumHits))
1451  continue; //a seed with more hits was found earlier
1452  if(locNumHits1 > locMaxSpiralNumHits)
1453  locMaxSpiralNumHits = locNumHits1;
1454  if(locNumHits2 > locMaxSpiralNumHits)
1455  locMaxSpiralNumHits = locNumHits2;
1456 
1457  //will use results from circle fits to make sure the seeds are turning in the correct direction.
1458  DSpiralParams_t locSpiralTurnParams;
1459  // try to determine if the spiral is turning inwards or outwards
1460  int locSpiralTurnRingFlag = 0;
1461  if(locSuperLayerSeed1->dCDCRingSeeds.size() == 1)
1462  locSpiralTurnRingFlag = ((locRing - 1)%4 > 1) ? 1 : -1;
1463  else if(loc_i == 0)
1464  locSpiralTurnRingFlag = -1; //turn on innermost ring
1465  else if(loc_i == (locSuperLayerSeed1->dCDCRingSeeds.size() - 1))
1466  locSpiralTurnRingFlag = 1; //turn on outermost ring
1467  else if(locSuperLayerSeed1->dCDCRingSeeds[loc_i + 1].hits.size() > locSuperLayerSeed1->dCDCRingSeeds[loc_i - 1].hits.size())
1468  locSpiralTurnRingFlag = -1; //more hits on outer ring than inner ring: turn on innermost ring
1469  else
1470  locSpiralTurnRingFlag = 1; //turn on outermost ring (if hit vector sizes are equal, assume outermost)
1471  locSpiralTurnParams.dSpiralTurnRingFlag = locSpiralTurnRingFlag;
1472  locSpiralTurnParams.dSpiralTurnRing = locRing;
1473  locSpiralTurnParams.dDefiniteSpiralTurnRingFlag = locAtLeastOneSeedDefiniteTurnFlag ? locSpiralTurnRingFlag : 0;
1474  locSuperLayerSeed1->dSpiralLinkParams[locSuperLayerSeed2->dSeedIndex] = locSpiralTurnParams;
1475  locSuperLayerSeed2->dSpiralLinkParams[locSuperLayerSeed1->dSeedIndex] = locSpiralTurnParams;
1476 
1477  if(DEBUG_LEVEL > 10)
1478  cout << "SL" << locSuperLayerSeed1->dSuperLayer << " Seed" << locSuperLayerSeed1->dSeedIndex << " Spiral-linked to SL" << locSuperLayerSeed2->dSuperLayer << " Seed" << locSuperLayerSeed2->dSeedIndex << ": Share No Hits, Ring = " << locRing << endl;
1479  }
1480  }
1481 
1482  return (locMaxSpiralNumHits > 0);
1483 }
1484 
1485 //--------------------------------
1486 // SearchFor_SpiralTurn_SingleSeed
1487 //--------------------------------
1489 {
1490  // search for a spiral turn contained within this DCDCSuperLayerSeed
1491  // signature is a ring with many hits
1492  int locMaxSpiralNumHits = 0; //can have more than one potential spiral turn on a seed: could have two tracks (or two spiral arms) turning near each other
1493  for(size_t loc_i = 0; loc_i < locSuperLayerSeed->dCDCRingSeeds.size(); ++loc_i)
1494  {
1495  int locRing = locSuperLayerSeed->dCDCRingSeeds[loc_i].ring;
1496  int locNumHits = locSuperLayerSeed->dCDCRingSeeds[loc_i].hits.size();
1497  if(locNumHits < locMaxSpiralNumHits)
1498  continue; //already found a potential spiral link in this seed with a > # of straws
1499 
1500  if(locNumHits < int(MIN_STRAWS_POTENTIAL_SPIRAL_TURN))
1501  continue; //not enough straws in seed
1502  locMaxSpiralNumHits = locNumHits;
1503 
1504  DSpiralParams_t locSpiralTurnParams;
1505  int locSpiralTurnRingFlag = ((locRing - 1)%4 > 1) ? 1 : -1;
1506  locSpiralTurnParams.dSpiralTurnRingFlag = locSpiralTurnRingFlag;
1507  locSpiralTurnParams.dSpiralTurnRing = locRing;
1508  locSpiralTurnParams.dDefiniteSpiralTurnRingFlag = (locNumHits >= int(MIN_STRAWS_DEFINITE_SPIRAL_TURN)) ? locSpiralTurnRingFlag : 0;
1509  locSuperLayerSeed->dSpiralLinkParams[locSuperLayerSeed->dSeedIndex] = locSpiralTurnParams;
1510  if(DEBUG_LEVEL > 10)
1511  cout << "SL" << locSuperLayerSeed->dSuperLayer << " Seed" << locSuperLayerSeed->dSeedIndex << " Self-spiral-linked: Ring = " << locRing << endl;
1512  }
1513  return (locMaxSpiralNumHits > 0);
1514 }
1515 
1516 //----------------------
1517 // Print_SuperLayerSeeds
1518 //----------------------
1520 {
1521  cout << "HITS BY SUPER LAYER & SEED INDEX:" << endl;
1522  for(unsigned int loc_i = 0; loc_i < 7; ++loc_i)
1523  {
1524  cout << " SUPER LAYER " << loc_i + 1 << ":" << endl;
1525  for(unsigned int loc_j = 0; loc_j < dSuperLayerSeeds[loc_i].size(); ++loc_j)
1526  {
1527  cout << " Seed Index " << loc_j << ":" << endl;
1528  DCDCSuperLayerSeed* locSuperLayerSeed = dSuperLayerSeeds[loc_i][loc_j];
1529  vector<DCDCTrkHit*> locHits;
1530  locSuperLayerSeed->Get_Hits(locHits);
1531  for(unsigned int loc_k = 0; loc_k < locHits.size(); ++loc_k)
1532  cout << "ring, straw, E (keV) = " << locHits[loc_k]->hit->wire->ring << ", " << locHits[loc_k]->hit->wire->straw << ", " << 1.0E6*locHits[loc_k]->hit->dE << endl;
1533  for(map<int, DSpiralParams_t>::iterator locIterator = locSuperLayerSeed->dSpiralLinkParams.begin(); locIterator != locSuperLayerSeed->dSpiralLinkParams.end(); ++locIterator)
1534  cout << "dSpiralLinkSeedIndex, dSpiralTurnRingFlag, dSpiralTurnRing, dDefiniteSpiralTurnRingFlag = " << locIterator->first << ", " << locIterator->second.dSpiralTurnRingFlag << ", " << locIterator->second.dSpiralTurnRing << ", " << locIterator->second.dDefiniteSpiralTurnRingFlag << endl;
1535  }
1536  }
1537 }
1538 
1539 /*********************************************************************************************************************************************************************/
1540 /************************************************************************ Build Track Circles ************************************************************************/
1541 /*********************************************************************************************************************************************************************/
1542 
1543 //-------------------
1544 // Build_TrackCircles
1545 //-------------------
1546 bool DTrackCandidate_factory_CDC::Build_TrackCircles(vector<DCDCTrackCircle*>& locCDCTrackCircles)
1547 {
1548  //return false if had to bail due to failure (i.e. too many track circles)
1549  //return true even if no track circles: it worked, it's just there aren't any
1550 
1551  //link DCDCSuperLayers together to form track circles
1552  locCDCTrackCircles.clear();
1553  for(unsigned int locOuterSuperLayer = 2; locOuterSuperLayer <= 7; ++locOuterSuperLayer)
1554  {
1555  unsigned int locInnerSuperLayer = locOuterSuperLayer - 1;
1556  if(locCDCTrackCircles.empty())
1557  {
1558  // no track circles yet: create new track circle objects using the super layer seeds in locInnerSuperLayer
1559  if(locInnerSuperLayer > MAX_SUPERLAYER_NEW_TRACK)
1560  return true; // don't create track circles beyond super layer MAX_SUPERLAYER_NEW_TRACK (e.g. knockout electrons from BCAL), return: no track circles!!!
1561  if(dSuperLayerSeeds[locInnerSuperLayer - 1].empty())
1562  continue; // no inner seeds, try next super layer
1563  //build new DCDCTrackCircle's: one for each super layer seed in this (inner) super layer
1564  for(size_t loc_j = 0; loc_j < dSuperLayerSeeds[locInnerSuperLayer - 1].size(); ++loc_j)
1565  {
1566  DCDCSuperLayerSeed* locSuperLayerSeed = dSuperLayerSeeds[locInnerSuperLayer - 1][loc_j];
1567  DCDCTrackCircle* locCDCTrackCircle = Get_Resource_CDCTrackCircle();
1568  if((locInnerSuperLayer == 1) || (locInnerSuperLayer == 4) || (locInnerSuperLayer == 7))
1569  locCDCTrackCircle->dSuperLayerSeeds_Axial.push_back(locSuperLayerSeed);
1570  else if((locInnerSuperLayer == 2) || (locInnerSuperLayer == 3))
1571  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.push_back(vector<DCDCSuperLayerSeed*>(1, locSuperLayerSeed));
1572  else
1573  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.push_back(vector<DCDCSuperLayerSeed*>(1, locSuperLayerSeed));
1574  locCDCTrackCircles.push_back(locCDCTrackCircle);
1575  }
1576  }
1577  //link existing track circles to DCDCSuperLayerSeed's in the outer super layer. Any unused DCDCSuperLayerSeed's will be used to make new track circles
1578  if(!Link_SuperLayers(locCDCTrackCircles, locOuterSuperLayer))
1579  return false; //too many track circles
1580  }
1581  //if still no tracks, make DCDCSuperLayerSeed's in super layer 7 into new tracks (if allowed (probably shouldn't be))
1582  if(locCDCTrackCircles.empty() && (MAX_SUPERLAYER_NEW_TRACK >= 7))
1583  {
1584  for(size_t loc_j = 0; loc_j < dSuperLayerSeeds[6].size(); ++loc_j)
1585  {
1586  DCDCSuperLayerSeed* locSuperLayerSeed = dSuperLayerSeeds[6][loc_j];
1587  DCDCTrackCircle* locCDCTrackCircle = Get_Resource_CDCTrackCircle();
1588  locCDCTrackCircle->dSuperLayerSeeds_Axial.push_back(locSuperLayerSeed);
1589  locCDCTrackCircles.push_back(locCDCTrackCircle);
1590  }
1591  }
1592  if(locCDCTrackCircles.empty())
1593  return true;
1594 
1595  //shouldn't be possible, but check to see if too many (should've failed sooner)
1596  if(locCDCTrackCircles.size() >= MAX_ALLOWED_TRACK_CIRCLES)
1597  {
1598  if(DEBUG_LEVEL > 10)
1599  cout << "Too many track circles; bailing" << endl;
1600  locCDCTrackCircles.clear();
1601  return true;
1602  }
1603 
1604  // Reject track circles if they are definitely a spiral arm that turns back outwards in its inner super layer
1605  Reject_DefiniteSpiralArms(locCDCTrackCircles);
1606  if(locCDCTrackCircles.empty())
1607  return true;
1608 
1609  // Reject track circles that don't contain at least one axial and one stereo super layer, unless that axial is super layer 1
1610  Drop_IncompleteGroups(locCDCTrackCircles);
1611  if(locCDCTrackCircles.empty())
1612  return true;
1613 
1614  if(DEBUG_LEVEL > 5)
1615  {
1616  cout << "LINKED TRACK CIRCLES" << endl;
1617  Print_TrackCircles(locCDCTrackCircles);
1618  }
1619 
1620  //fit circles to the DCDCTrackCircle's. This will reject fits if they aren't very good
1621  //1st false: fit all circles //2nd false: don't add intersections between stereo layers (wait until specific stereo super layers have been selected)
1622  Fit_Circles(locCDCTrackCircles, false, false);
1623  if(locCDCTrackCircles.empty())
1624  return true;
1625  stable_sort(locCDCTrackCircles.begin(), locCDCTrackCircles.end(), CDCSortByChiSqPerNDFDecreasing); //sort by circle-fit weighted chisq/ndf (largest first)
1626 
1627  if(DEBUG_LEVEL > 5)
1628  {
1629  cout << "post circle fit" << endl;
1630  Print_TrackCircles(locCDCTrackCircles);
1631  }
1632 
1633  return true;
1634 }
1635 
1636 //-----------------
1637 // Link_SuperLayers
1638 //-----------------
1639 bool DTrackCandidate_factory_CDC::Link_SuperLayers(vector<DCDCTrackCircle*>& locCDCTrackCircles, unsigned int locOuterSuperLayer)
1640 {
1641  /// Loop over the DCDCTrackCircles and the next super layer seeds and compare the positions of
1642  /// their first and last hits to see if we should link them together.
1643  /// If at <= MAX_SUPERLAYER_NEW_TRACK: Any seeds from the outer super layer that are not linked will be added to the <i>DCDCTrackCircle</i> list.
1644  /// Will try to link by skipping a super layer if a link was not previously performed and ENABLE_DEAD_HV_BOARD_LINKING is set to true (default false)
1645 
1646  if(DEBUG_LEVEL > 3)
1647  cout << "Linking seeds, locOuterSuperLayer = " << locOuterSuperLayer << endl;
1648 
1649  //Link locCDCTrackCircles's to the next super layer seeds
1650  unsigned int locInnerSuperLayer = locOuterSuperLayer - 1;
1651  if((locInnerSuperLayer == 1) || (locInnerSuperLayer == 4)) //else linking from stereo
1652  Link_SuperLayers_FromAxial(locCDCTrackCircles, locOuterSuperLayer, locInnerSuperLayer);
1653  else if((locOuterSuperLayer == 4) || (locOuterSuperLayer == 7))
1654  {
1655  if(!Link_SuperLayers_FromStereo_ToAxial(locCDCTrackCircles, locOuterSuperLayer, locInnerSuperLayer))
1656  return false; //linking failed: too many track circles
1657  }
1658  else
1659  Link_SuperLayers_FromStereo_ToStereo(locCDCTrackCircles, locOuterSuperLayer, locInnerSuperLayer);
1660  if(DEBUG_LEVEL > 25)
1661  {
1662  cout << "Link-to SL" << locOuterSuperLayer << ", v1" << endl;
1663  Print_TrackCircles(locCDCTrackCircles);
1664  }
1665 
1666  //For DCDCTrackCircle's that failed to link, try checking to see if can link to the previous super layer (e.g. a HV board was dead)
1667  if(ENABLE_DEAD_HV_BOARD_LINKING && (locInnerSuperLayer != 1))
1668  {
1669  --locInnerSuperLayer;
1670  if(DEBUG_LEVEL > 3)
1671  cout << "Try to skip super layer (e.g. HV board dead); new inner super layer = " << locInnerSuperLayer << endl;
1672  if((locInnerSuperLayer == 1) || (locInnerSuperLayer == 4))
1673  Link_SuperLayers_FromAxial(locCDCTrackCircles, locOuterSuperLayer, locInnerSuperLayer);
1674  else if((locOuterSuperLayer == 4) || (locOuterSuperLayer == 7))
1675  {
1676  if(!Link_SuperLayers_FromStereo_ToAxial(locCDCTrackCircles, locOuterSuperLayer, locInnerSuperLayer))
1677  return false; //linking failed: too many track circles
1678  }
1679  else
1680  Link_SuperLayers_FromStereo_ToStereo(locCDCTrackCircles, locOuterSuperLayer, locInnerSuperLayer);
1681  if(DEBUG_LEVEL > 25)
1682  {
1683  cout << "Link-to SL" << locOuterSuperLayer << ", v2" << endl;
1684  Print_TrackCircles(locCDCTrackCircles);
1685  }
1686  }
1687 
1688  // For outer seeds that failed to link, save as new track circles (even if they are stereo layers), UNLESS they are after MAX_SUPERLAYER_NEW_TRACK
1689  // UNLESS: a region at about the same phi in a previous super layer had a very high density of hits (such that all seeds in it were rejected)
1690  // Don't want to create new tracks in this case!
1691  if(locOuterSuperLayer <= MAX_SUPERLAYER_NEW_TRACK)
1692  {
1693  if(DEBUG_LEVEL > 3)
1694  cout << "Save any unlinked as new track circles" << endl;
1695  for(size_t loc_i = 0; loc_i < dSuperLayerSeeds[locOuterSuperLayer - 1].size(); ++loc_i)
1696  {
1697  DCDCSuperLayerSeed* locSuperLayerSeed = dSuperLayerSeeds[locOuterSuperLayer - 1][loc_i];
1698  if(locSuperLayerSeed->linked)
1699  continue; //previously linked, don't create new object
1700  //make sure this seed doesn't correspond to a region in phi where all of the seeds were deleted earlier
1701  //calc phi range of seed
1702  double locSeedFirstPhi, locSeedLastPhi;
1703  Calc_SuperLayerPhiRange(locSuperLayerSeed, locSeedFirstPhi, locSeedLastPhi);
1704  bool locHitDensityPreviouslyTooHighFlag = false;
1705  for(size_t loc_j = 1; loc_j < locOuterSuperLayer; ++loc_j)
1706  {
1707  for(size_t loc_k = 0; loc_k < dRejectedPhiRegions[loc_j].size(); ++loc_k)
1708  {
1709  if(!Check_IfPhiRangesOverlap(locSeedFirstPhi, locSeedLastPhi, dRejectedPhiRegions[loc_j][loc_k].first, dRejectedPhiRegions[loc_j][loc_k].second))
1710  continue;
1711  locHitDensityPreviouslyTooHighFlag = true;
1712  break;
1713  }
1714  if(locHitDensityPreviouslyTooHighFlag)
1715  break;
1716  }
1717  if(locHitDensityPreviouslyTooHighFlag)
1718  continue;
1719  //create new track circle
1720  if(DEBUG_LEVEL > 10)
1721  cout << "Unlinked seed; create new track circle: super layer & seed index = " << locSuperLayerSeed->dSuperLayer << ", " << locSuperLayerSeed->dSeedIndex << endl;
1722  if(locCDCTrackCircles.size() >= MAX_ALLOWED_TRACK_CIRCLES)
1723  {
1724  if(DEBUG_LEVEL > 10)
1725  cout << "Too many track circles; bailing" << endl;
1726  locCDCTrackCircles.clear();
1727  return false;
1728  }
1729  DCDCTrackCircle* locCDCTrackCircle = Get_Resource_CDCTrackCircle();
1730  if((locOuterSuperLayer == 4) || (locOuterSuperLayer == 7))
1731  locCDCTrackCircle->dSuperLayerSeeds_Axial.push_back(locSuperLayerSeed);
1732  else if((locOuterSuperLayer == 2) || (locOuterSuperLayer == 3))
1733  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.push_back(vector<DCDCSuperLayerSeed*>(1, locSuperLayerSeed));
1734  else
1735  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.push_back(vector<DCDCSuperLayerSeed*>(1, locSuperLayerSeed));
1736  locCDCTrackCircles.push_back(locCDCTrackCircle);
1737  }
1738  if(DEBUG_LEVEL > 25)
1739  {
1740  cout << "Link-to SL" << locOuterSuperLayer << ", v3" << endl;
1741  Print_TrackCircles(locCDCTrackCircles);
1742  }
1743  }
1744 
1745  return true;
1746 }
1747 
1748 //---------------------------
1749 // Link_SuperLayers_FromAxial
1750 //---------------------------
1751 void DTrackCandidate_factory_CDC::Link_SuperLayers_FromAxial(vector<DCDCTrackCircle*>& locCDCTrackCircles, unsigned int locOuterSuperLayer, unsigned int locInnerSuperLayer)
1752 {
1753  //Link locCDCTrackCircles from an axial super layer to a stereo super layer (must be stereo: cannot skip two (both stereo) super layers)
1754  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
1755  {
1756  DCDCTrackCircle* locCDCTrackCircle = locCDCTrackCircles[loc_i];
1757  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
1758  continue; // no axial super layer seeds to link from
1759  DCDCSuperLayerSeed* locSuperLayerSeed1 = locCDCTrackCircle->dSuperLayerSeeds_Axial.back();
1760  if(locSuperLayerSeed1->dSuperLayer != locInnerSuperLayer)
1761  continue; // e.g. the track ended earlier
1762  if(DEBUG_LEVEL > 10)
1763  cout << "Seed 1 Super Layer, Seed Index = " << locSuperLayerSeed1->dSuperLayer << ", " << locSuperLayerSeed1->dSeedIndex << endl;
1764  if(!Check_IfShouldAttemptLink(locSuperLayerSeed1, true))
1765  continue; //don't attempt seed link if the inner seed was a definite spiral turn that was turning back inwards, etc.
1766 
1767  // if trying to skip a layer, first check to make sure this seed wasn't already linked (to layer "locInnerSuperLayer + 1")
1768  if((locInnerSuperLayer == 1) && (!locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.empty()))
1769  continue; //already linked to some inner stereo seeds
1770  else if((locInnerSuperLayer == 4) && (!locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.empty()))
1771  continue; //already linked to some outer stereo seeds
1772 
1773  for(size_t loc_j = 0; loc_j < dSuperLayerSeeds[locOuterSuperLayer - 1].size(); ++loc_j)
1774  {
1775  DCDCSuperLayerSeed* locSuperLayerSeed2 = dSuperLayerSeeds[locOuterSuperLayer - 1][loc_j];
1776  if(DEBUG_LEVEL > 10)
1777  cout << "Seed 2 Super Layer, Seed Index = " << locSuperLayerSeed2->dSuperLayer << ", " << locSuperLayerSeed2->dSeedIndex << endl;
1778  if(!Check_IfShouldAttemptLink(locSuperLayerSeed2, false))
1779  continue; //don't attempt seed link if the outer seed was a definite spiral turn that was turning back outwards, etc.
1780  if(DEBUG_LEVEL > 10)
1781  cout << "Attempting Seed Link" << endl;
1782  if(!Attempt_SeedLink(locSuperLayerSeed1, locSuperLayerSeed2)) //see if seeds are nearby enough to link
1783  continue;
1784  //LINK SUCCESSFUL!!
1785  if(DEBUG_LEVEL > 10)
1786  cout << "LINK SUCCESSFUL" << endl;
1787  locSuperLayerSeed1->linked = true;
1788  locSuperLayerSeed2->linked = true;
1789 
1790  //create new group of stereo seeds (assumes linking to stereo: cannot axial (would skip too many))
1791  if(locOuterSuperLayer < 4)
1792  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.push_back(vector<DCDCSuperLayerSeed*>(1, locSuperLayerSeed2));
1793  else
1794  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.push_back(vector<DCDCSuperLayerSeed*>(1, locSuperLayerSeed2));
1795  }
1796  }
1797 }
1798 
1799 //------------------------------------
1800 // Link_SuperLayers_FromStereo_ToAxial
1801 //------------------------------------
1802 bool DTrackCandidate_factory_CDC::Link_SuperLayers_FromStereo_ToAxial(vector<DCDCTrackCircle*>& locCDCTrackCircles, unsigned int locOuterSuperLayer, unsigned int locInnerSuperLayer)
1803 {
1804  // Link from a stereo super layer to an axial super layer. Unfortunately, this is extremely messy.
1805  //If you're editing this, I stronly suggest reading the simpler Link_SuperLayers_FromStereo_ToStereo function to make sure you understand it first. Good luck! :)
1806 
1807  //since linking to axial, will create new track circles (one for each unique combo of axial seeds)
1808  vector<DCDCTrackCircle*> locNewCDCTrackCircles; //will eventually return this vector (by setting locCDCTrackCircles to it at the end)
1809 
1810  // first save all track circles for output (into locNewCDCTrackCircles) that definitely will NOT be linked from:
1811  //those that already have an axial layer greater than the stereo we're linking from
1812  //this happens when trying to skip a super layer (e.g. a dead hv board), but this circle link was linked successfully
1813  //do this first, so that if an axial combo is created later that somehow is identical (e.g. due to skipping a super layer due to a dead HV board)
1814  //the stereo seeds will just be merged with the already existing one
1815  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
1816  {
1817  DCDCTrackCircle* locCDCTrackCircle = locCDCTrackCircles[loc_i];
1818  if(!locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
1819  {
1820  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.back()->dSuperLayer > locInnerSuperLayer)
1821  {
1822  locNewCDCTrackCircles.push_back(locCDCTrackCircle);
1823  continue;
1824  }
1825  }
1826  }
1827 
1828  // loop over track circles
1829  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
1830  {
1831  DCDCTrackCircle* locCDCTrackCircle = locCDCTrackCircles[loc_i];
1832 
1833  // if trying to skip a layer, first check to make sure this seed wasn't already linked (to layer "locInnerSuperLayer + 1")
1834  // axial checked here, stereo checked for each stereo series below
1835  if(!locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
1836  {
1837  // circle already saved in the output (above), so just skip linking here
1838  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.back()->dSuperLayer > locInnerSuperLayer)
1839  continue;
1840  }
1841 
1842  // determine if linking from the stereo seeds stored in the dSuperLayerSeeds_InnerStereo or dSuperLayerSeeds_OuterStereo vectors
1843  bool locFromInnerStereoFlag = (locInnerSuperLayer < 4);
1844  if(!locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
1845  {
1846  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.back()->dSuperLayer != 4)
1847  locFromInnerStereoFlag = true; //middle axial layer is missing, store stereo layer as inner
1848  }
1849 
1850  //get a vector containing all of the series's of seeds to loop over
1851  vector<vector<DCDCSuperLayerSeed*> > locPreLinkedCDCSuperLayerSeeds;
1852  if(locFromInnerStereoFlag) //if on outer stereo seeds but axial seed 4 is missing, use inner stereo seeds
1853  locPreLinkedCDCSuperLayerSeeds = locCDCTrackCircle->dSuperLayerSeeds_InnerStereo;
1854  else //use outer stereo seeds
1855  locPreLinkedCDCSuperLayerSeeds = locCDCTrackCircle->dSuperLayerSeeds_OuterStereo; //for looping over
1856 
1857  bool locTrackCircleSavedFlag = false; //make sure that this track circle is saved in the output even if no future link is found
1858  //loop over each series of stereo seeds
1859  for(size_t loc_j = 0; loc_j < locPreLinkedCDCSuperLayerSeeds.size(); ++loc_j)
1860  {
1861  //get the last DCDCSuperLayerSeed in this stereo seed series
1862  vector<DCDCSuperLayerSeed*> locStereoSeedSeries = locPreLinkedCDCSuperLayerSeeds[loc_j];
1863  DCDCSuperLayerSeed* locSuperLayerSeed1 = locPreLinkedCDCSuperLayerSeeds[loc_j].back();
1864  if(DEBUG_LEVEL > 10)
1865  cout << "Seed 1 Super Layer, Seed Index = " << locSuperLayerSeed1->dSuperLayer << ", " << locSuperLayerSeed1->dSeedIndex << endl;
1866 
1867  bool locInnerSeedLinkSuccessfulFlag = false;
1868  //don't attempt seed link if wrong super layer, or if the inner seed was a definite spiral turn that was turning back inwards, etc.
1869  if((locSuperLayerSeed1->dSuperLayer == locInnerSuperLayer) && Check_IfShouldAttemptLink(locSuperLayerSeed1, true))
1870  {
1871  //attempt to link to the outer superlayer
1872  for(size_t loc_k = 0; loc_k < dSuperLayerSeeds[locOuterSuperLayer - 1].size(); ++loc_k)
1873  {
1874  DCDCSuperLayerSeed* locSuperLayerSeed2 = dSuperLayerSeeds[locOuterSuperLayer - 1][loc_k];
1875  if(DEBUG_LEVEL > 10)
1876  cout << "Seed 2 Super Layer, Seed Index = " << locSuperLayerSeed2->dSuperLayer << ", " << locSuperLayerSeed2->dSeedIndex << endl;
1877  if(!Check_IfShouldAttemptLink(locSuperLayerSeed2, false))
1878  continue; //don't attempt seed link if the outer seed was a definite spiral turn that was turning back outwards, etc.
1879  if(DEBUG_LEVEL > 10)
1880  cout << "Attempting Seed Link" << endl;
1881  if(!Attempt_SeedLink(locSuperLayerSeed1, locSuperLayerSeed2)) //see if seeds are nearby enough to link
1882  continue;
1883  //LINK SUCCESSFUL!!
1884  if(DEBUG_LEVEL > 10)
1885  cout << "LINK SUCCESSFUL" << endl;
1886  locSuperLayerSeed1->linked = true;
1887  locSuperLayerSeed2->linked = true;
1888  locInnerSeedLinkSuccessfulFlag = true;
1889 
1890  //make new vector of axial seeds
1891  vector<DCDCSuperLayerSeed*> locNewCDCSuperLayerSeeds_Axial = locCDCTrackCircle->dSuperLayerSeeds_Axial;
1892  locNewCDCSuperLayerSeeds_Axial.push_back(locSuperLayerSeed2);
1893 
1894  //see if should create new DCDCTrackCircle object (axial combo is unique) or use a (probably recently created) existing one (it is not unique)
1895  DCDCTrackCircle* locNewCDCTrackCircle = NULL;
1896  for(size_t loc_l = 0; loc_l < locNewCDCTrackCircles.size(); ++loc_l)
1897  {
1898  if(locNewCDCSuperLayerSeeds_Axial != locNewCDCTrackCircles[loc_l]->dSuperLayerSeeds_Axial)
1899  continue;
1900  //all axial layers are identical: use previous object
1901  locNewCDCTrackCircle = locNewCDCTrackCircles[loc_l];
1902  }
1903  if(locNewCDCTrackCircle == NULL)
1904  {
1905  //new combination of axial layers, create new object
1906  if(locNewCDCTrackCircles.size() >= MAX_ALLOWED_TRACK_CIRCLES)
1907  {
1908  if(DEBUG_LEVEL > 10)
1909  cout << "Too many track circles; bailing" << endl;
1910  locCDCTrackCircles.clear();
1911  return false;
1912  }
1913  locNewCDCTrackCircle = Get_Resource_CDCTrackCircle();
1914  locNewCDCTrackCircle->dSuperLayerSeeds_Axial = locNewCDCSuperLayerSeeds_Axial;
1915  if(!locFromInnerStereoFlag) //if on outer stereo, keep inner stereo results (but not outer stereo!!: will save below)
1916  locNewCDCTrackCircle->dSuperLayerSeeds_InnerStereo = locCDCTrackCircle->dSuperLayerSeeds_InnerStereo;
1917  locNewCDCTrackCircles.push_back(locNewCDCTrackCircle); //store new circle for return
1918  locTrackCircleSavedFlag = true;
1919  }
1920  //save this current series of stereo seeds
1921  if(locFromInnerStereoFlag)
1922  locNewCDCTrackCircle->dSuperLayerSeeds_InnerStereo.push_back(locStereoSeedSeries);
1923  else
1924  locNewCDCTrackCircle->dSuperLayerSeeds_OuterStereo.push_back(locStereoSeedSeries);
1925  }
1926  }
1927  if(!locInnerSeedLinkSuccessfulFlag)
1928  {
1929  //this inner seed series was not linked to an axial seed: need to make sure this group is still saved in the "new" vector
1930  //see if should create new DCDCTrackCircle object (axial combo is unique) or use a (probably recently created) existing one (it is not unique)
1931  DCDCTrackCircle* locNewCDCTrackCircle = NULL;
1932  for(size_t loc_l = 0; loc_l < locNewCDCTrackCircles.size(); ++loc_l)
1933  {
1934  if(locCDCTrackCircle->dSuperLayerSeeds_Axial != locNewCDCTrackCircles[loc_l]->dSuperLayerSeeds_Axial)
1935  continue;
1936  //all axial layers are identical: use previous object
1937  locNewCDCTrackCircle = locNewCDCTrackCircles[loc_l];
1938  }
1939  if(locNewCDCTrackCircle == NULL)
1940  {
1941  //new combination of axial layers, create new object
1942  if(locNewCDCTrackCircles.size() >= MAX_ALLOWED_TRACK_CIRCLES)
1943  {
1944  if(DEBUG_LEVEL > 10)
1945  cout << "Too many track circles; bailing" << endl;
1946  locCDCTrackCircles.clear();
1947  return false;
1948  }
1949  locNewCDCTrackCircle = Get_Resource_CDCTrackCircle();
1950  locNewCDCTrackCircle->dSuperLayerSeeds_Axial = locCDCTrackCircle->dSuperLayerSeeds_Axial;
1951  if(!locFromInnerStereoFlag) //if on outer stereo, keep inner stereo results (but not outer stereo!!: will save below)
1952  locNewCDCTrackCircle->dSuperLayerSeeds_InnerStereo = locCDCTrackCircle->dSuperLayerSeeds_InnerStereo;
1953  locNewCDCTrackCircles.push_back(locNewCDCTrackCircle); //store new circle for return
1954  locTrackCircleSavedFlag = true;
1955  }
1956  //save this current series of stereo seeds
1957  if(locFromInnerStereoFlag)
1958  locNewCDCTrackCircle->dSuperLayerSeeds_InnerStereo.push_back(locStereoSeedSeries);
1959  else
1960  locNewCDCTrackCircle->dSuperLayerSeeds_OuterStereo.push_back(locStereoSeedSeries);
1961  }
1962  }
1963  //if true: no combination of stereo seeds from this track circle was linked as a new object, keep as a unique combination
1964  if(!locTrackCircleSavedFlag)
1965  locNewCDCTrackCircles.push_back(locCDCTrackCircle);
1966  }
1967 
1968  locCDCTrackCircles = locNewCDCTrackCircles; //"return" "new" track circle objects
1969  return true;
1970 }
1971 
1972 //-------------------------------------
1973 // Link_SuperLayers_FromStereo_ToStereo
1974 //-------------------------------------
1975 void DTrackCandidate_factory_CDC::Link_SuperLayers_FromStereo_ToStereo(vector<DCDCTrackCircle*>& locCDCTrackCircles, unsigned int locOuterSuperLayer, unsigned int locInnerSuperLayer)
1976 {
1977  // Link from a stereo super layer to a stereo super layer.
1978 
1979  // loop over track circles
1980  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
1981  {
1982  DCDCTrackCircle* locCDCTrackCircle = locCDCTrackCircles[loc_i];
1983 
1984  // if trying to skip a layer, first check to make sure this seed wasn't already linked (to layer "locInnerSuperLayer + 1")
1985  // axial checked here, stereo checked for each stereo series below
1986  if(!locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
1987  {
1988  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.back()->dSuperLayer > locInnerSuperLayer)
1989  continue;
1990  }
1991 
1992  // determine if linking from the stereo seeds stored in the dSuperLayerSeeds_InnerStereo or dSuperLayerSeeds_OuterStereo vectors
1993  bool locFromInnerStereoFlag = (locInnerSuperLayer < 4);
1994  if(!locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
1995  {
1996  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.back()->dSuperLayer != 4)
1997  locFromInnerStereoFlag = true; //middle axial layer is missing, store stereo layer as inner
1998  }
1999 
2000  //get series of seeds to loop over
2001  vector<vector<DCDCSuperLayerSeed*> > locPreLinkedCDCSuperLayerSeeds;
2002  if(locFromInnerStereoFlag)
2003  {
2004  //if on outer stereo seeds but axial seed 4 is missing, use inner stereo seeds
2005  locPreLinkedCDCSuperLayerSeeds = locCDCTrackCircle->dSuperLayerSeeds_InnerStereo;
2006  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.clear(); //reset the existing combos: will re-fill below with the new combos
2007  }
2008  else
2009  {
2010  //use outer stereo seeds
2011  locPreLinkedCDCSuperLayerSeeds = locCDCTrackCircle->dSuperLayerSeeds_OuterStereo; //for looping over
2012  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.clear(); //reset the existing combos: will re-fill below with the new combos
2013  }
2014 
2015  //loop over each series of stereo seeds
2016  for(size_t loc_j = 0; loc_j < locPreLinkedCDCSuperLayerSeeds.size(); ++loc_j)
2017  {
2018  //get the last DCDCSuperLayerSeed in this stereo seed series
2019  vector<DCDCSuperLayerSeed*> locStereoSeedSeries = locPreLinkedCDCSuperLayerSeeds[loc_j];
2020  DCDCSuperLayerSeed* locSuperLayerSeed1 = locPreLinkedCDCSuperLayerSeeds[loc_j].back();
2021  if(DEBUG_LEVEL > 10)
2022  cout << "Seed 1 Super Layer, Seed Index = " << locSuperLayerSeed1->dSuperLayer << ", " << locSuperLayerSeed1->dSeedIndex << endl;
2023 
2024  bool locInnerSeedLinkSuccessfulFlag = false;
2025  //don't attempt seed link if wrong super layer, or if the inner seed was a definite spiral turn that was turning back inwards, etc.
2026  if((locSuperLayerSeed1->dSuperLayer == locInnerSuperLayer) && Check_IfShouldAttemptLink(locSuperLayerSeed1, true))
2027  {
2028  //attempt to link to the outer superlayer
2029  for(size_t loc_k = 0; loc_k < dSuperLayerSeeds[locOuterSuperLayer - 1].size(); ++loc_k)
2030  {
2031  DCDCSuperLayerSeed* locSuperLayerSeed2 = dSuperLayerSeeds[locOuterSuperLayer - 1][loc_k];
2032  if(DEBUG_LEVEL > 10)
2033  cout << "Seed 2 Super Layer, Seed Index = " << locSuperLayerSeed2->dSuperLayer << ", " << locSuperLayerSeed2->dSeedIndex << endl;
2034  if(!Check_IfShouldAttemptLink(locSuperLayerSeed2, false))
2035  continue; //don't attempt seed link if the outer seed was a definite spiral turn that was turning back outwards, etc.
2036  if(DEBUG_LEVEL > 10)
2037  cout << "Attempting Seed Link" << endl;
2038  if(!Attempt_SeedLink(locSuperLayerSeed1, locSuperLayerSeed2)) //see if seeds are nearby enough to link
2039  continue;
2040  //LINK SUCCESSFUL!!
2041  if(DEBUG_LEVEL > 10)
2042  cout << "LINK SUCCESSFUL" << endl;
2043  locSuperLayerSeed1->linked = true;
2044  locSuperLayerSeed2->linked = true;
2045  locInnerSeedLinkSuccessfulFlag = true;
2046 
2047  //create vector of new stereo seed series
2048  vector<DCDCSuperLayerSeed*> locNewStereoSeedSeries = locStereoSeedSeries;
2049  locNewStereoSeedSeries.push_back(locSuperLayerSeed2);
2050 
2051  //save new combination of stereo seeds
2052  if(locFromInnerStereoFlag)
2053  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.push_back(locNewStereoSeedSeries);
2054  else //outer and middle axial layer isn't missing
2055  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.push_back(locNewStereoSeedSeries);
2056  }
2057  }
2058  if(!locInnerSeedLinkSuccessfulFlag)
2059  {
2060  //failed to match, but keep seed series
2061  if(locFromInnerStereoFlag)
2062  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.push_back(locStereoSeedSeries);
2063  else //outer and middle axial layer isn't missing
2064  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.push_back(locStereoSeedSeries);
2065  }
2066  }
2067  }
2068 }
2069 
2070 //--------------------------
2071 // Check_IfShouldAttemptLink
2072 //--------------------------
2073 bool DTrackCandidate_factory_CDC::Check_IfShouldAttemptLink(const DCDCSuperLayerSeed* locSuperLayerSeed, bool locInnerSeedFlag)
2074 {
2075  // don't attempt linking if a definite spiral turn on one of the seeds is turning in the wrong direction
2076  if(locSuperLayerSeed->dSpiralLinkParams.empty())
2077  return true; //should definitely attempt it if not a spiral turn
2078 
2079  //get spiral link information
2080  const map<int, DSpiralParams_t>& locSpiralLinkParams = locSuperLayerSeed->dSpiralLinkParams;
2081  bool locSelfLinkFlag = (locSpiralLinkParams.find(locSuperLayerSeed->dSeedIndex) != locSpiralLinkParams.end()); //true if spiral-link is within itself
2082 
2083  // determine if turning inwards, outwards, or indeterminate
2084  bool locIsTurningOutwardsFlag = false;
2085  bool locIsTurningInwardsFlag = false;
2086  map<int, DSpiralParams_t>::const_iterator locIterator;
2087  for(locIterator = locSuperLayerSeed->dSpiralLinkParams.begin(); locIterator != locSuperLayerSeed->dSpiralLinkParams.end(); ++locIterator)
2088  {
2089  if(locIterator->second.dDefiniteSpiralTurnRingFlag == -1)
2090  locIsTurningOutwardsFlag = true;
2091  else if(locIterator->second.dDefiniteSpiralTurnRingFlag == 1)
2092  locIsTurningInwardsFlag = true;
2093  }
2094  if(locIsTurningOutwardsFlag == locIsTurningInwardsFlag)
2095  return true; //either not a definite spiral turn (both are false), or indeterminate turning direction (both are true)
2096 
2097  //check spiral turn direction
2098  if(locInnerSeedFlag)
2099  {
2100  if(!locSelfLinkFlag)
2101  {
2102  if(locIsTurningInwardsFlag)
2103  {
2104  //spiral turn not linked to itself, inner seed is turning inwards : don't link to next super layer
2105  if(DEBUG_LEVEL > 10)
2106  cout << "Seed1 part of spiral turn in different direction, don't link it here." << endl;
2107  return false;
2108  }
2109  }
2110  else if(locIsTurningOutwardsFlag)
2111  {
2112  //spiral turn linked to itself (single ring), on ring in inner-half of the inner super layer used for matching : don't link to next super layer
2113  if(DEBUG_LEVEL > 10)
2114  cout << "Seed1 part of spiral turn in different direction, don't link it here." << endl;
2115  return false;
2116  }
2117  }
2118  else
2119  {
2120  if(!locSelfLinkFlag)
2121  {
2122  if(locIsTurningOutwardsFlag)
2123  {
2124  //spiral turn not linked to itself, outer seed is turning outwards : don't link to previous super layer
2125  if(DEBUG_LEVEL > 10)
2126  cout << "Seed2 part of spiral turn in different direction, don't link it here." << endl;
2127  return false;
2128  }
2129  }
2130  else if(locIsTurningInwardsFlag)
2131  {
2132  //spiral turn linked to itself (single ring), on ring in outer-half of the outer super layer used for matching : don't link to previous super layer
2133  if(DEBUG_LEVEL > 10)
2134  cout << "Seed2 part of spiral turn in different direction, don't link it here." << endl;
2135  return false;
2136  }
2137  }
2138  return true;
2139 }
2140 
2141 //-----------------
2142 // Attempt_SeedLink
2143 //-----------------
2145 {
2146  //locSuperLayerSeed1 should be the inner of the two
2147  wire_direction_t locWireDirection1 = locSuperLayerSeed1->dWireOrientation;
2148  DCDCRingSeed& locRingSeed1 = locSuperLayerSeed1->dCDCRingSeeds.back(); //largest ring of inner seed selected
2149 
2150  //locSuperLayerSeed2 should be the outer of the two
2151  wire_direction_t locWireDirection2 = locSuperLayerSeed2->dWireOrientation;
2152  DCDCRingSeed& locRingSeed2 = locSuperLayerSeed2->dCDCRingSeeds.front(); //smallest ring of outer seed selected
2153 
2154  return Attempt_SeedLink(locRingSeed1, locRingSeed2, locWireDirection1, locWireDirection2);
2155 }
2156 
2157 //-----------------
2158 // Attempt_SeedLink
2159 //-----------------
2160 bool DTrackCandidate_factory_CDC::Attempt_SeedLink(DCDCRingSeed& locRingSeed1, DCDCRingSeed& locRingSeed2, wire_direction_t locWireDirection1, wire_direction_t locWireDirection2)
2161 {
2162  //attempt seed link between ring-seeds
2163  //should only be called when linking super layers together, and when attempting to link to unused hits
2164  vector<DCDCTrkHit*> &hits1 = locRingSeed1.hits;
2165  if(hits1.empty())
2166  return false;
2167 
2168  vector<DCDCTrkHit*> &hits2 = locRingSeed2.hits;
2169  if(hits2.empty())
2170  return false;
2171 
2172  const DCDCWire* wire1 = hits1[0]->hit->wire;
2173  const DCDCWire* wire2 = hits2[0]->hit->wire;
2174 
2175  // Determine the minimum distance between the two sets of hits
2176  double locMinDist2 = MinDist2(locRingSeed1, locRingSeed2);
2177 
2178  // Determine the maximum-allowed transverse distance for linking: is dependent on the orientation of the wires
2179  //if axial, distance is MAX_HIT_DIST
2180  //if stereo, distance is MAX_HIT_DIST + 1/2 of the length of the projection of the straw onto the X-Y plane
2181  //why 1/2? because the wire position (origin) is reported at the midpoint of the straw
2182  double locMaxDist2;
2183  if((locWireDirection1 == WIRE_DIRECTION_AXIAL) && (locWireDirection2 == WIRE_DIRECTION_AXIAL))
2184  locMaxDist2 = MAX_HIT_DIST2;
2185  else if((locWireDirection1 == WIRE_DIRECTION_AXIAL) && (locWireDirection2 != WIRE_DIRECTION_AXIAL))
2186  {
2187  locMaxDist2 = MAX_HIT_DIST + 0.5*wire2->L*fabs(sin(wire2->stereo));
2188  locMaxDist2 *= locMaxDist2;
2189  }
2190  else if((locWireDirection1 != WIRE_DIRECTION_AXIAL) && (locWireDirection2 == WIRE_DIRECTION_AXIAL))
2191  {
2192  locMaxDist2 = MAX_HIT_DIST + 0.5*wire1->L*fabs(sin(wire1->stereo));
2193  locMaxDist2 *= locMaxDist2;
2194  }
2195  else if((locWireDirection1 == WIRE_DIRECTION_STEREORIGHT) && (locWireDirection2 == WIRE_DIRECTION_STEREOLEFT))
2196  {
2197  locMaxDist2 = MAX_HIT_DIST + 0.5*wire1->L*fabs(sin(wire1->stereo)) + 0.5*wire2->L*fabs(sin(wire2->stereo));
2198  locMaxDist2 *= locMaxDist2;
2199  }
2200  else if((locWireDirection1 == WIRE_DIRECTION_STEREOLEFT) && (locWireDirection2 == WIRE_DIRECTION_STEREORIGHT))
2201  {
2202  locMaxDist2 = MAX_HIT_DIST + 0.5*wire1->L*fabs(sin(wire1->stereo)) + 0.5*wire2->L*fabs(sin(wire2->stereo));
2203  locMaxDist2 *= locMaxDist2;
2204  }
2205  else //both stereo left or right
2206  locMaxDist2 = MAX_HIT_DIST2;
2207 
2208  double dr = wire2->origin.Perp() - wire1->origin.Perp();
2209  if(DEBUG_LEVEL > 20)
2210  cout << "locMinDist2, locMaxDist2, dr = " << locMinDist2 << ", " << locMaxDist2 << ", " << dr << endl;
2211 
2212  //calculate transverse distance, return whether or not it is too large
2213  double locTransverseDist2 = locMinDist2 - dr*dr;
2214  return (locTransverseDist2 < locMaxDist2);
2215 }
2216 
2217 //-------------------
2218 // Print_TrackCircles
2219 //-------------------
2220 void DTrackCandidate_factory_CDC::Print_TrackCircles(vector<DCDCTrackCircle*>& locCDCTrackCircles)
2221 {
2222  cout << "Track Circle Super Layer Seeds (Axial, Inner/Outer Stereo):" << endl;
2223  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
2224  {
2225  cout << "Track Circle Index = " << loc_i << endl;
2226  Print_TrackCircle(locCDCTrackCircles[loc_i]);
2227  }
2228 }
2229 
2230 //------------------
2231 // Print_TrackCircle
2232 //------------------
2234 {
2235  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_Axial.size(); ++loc_j)
2236  cout << "Axial Super Layer, Seed Index = " << locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_j]->dSuperLayer << ", " << locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_j]->dSeedIndex << endl;
2237  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.size(); ++loc_j)
2238  {
2239  cout << "Inner Stereo Series " << loc_j << ":" << endl;
2240  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_j].size(); ++loc_k)
2241  cout << "Super Layer, Seed Index = " << locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_j][loc_k]->dSuperLayer << ", " << locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_j][loc_k]->dSeedIndex << endl;
2242  }
2243  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.size(); ++loc_j)
2244  {
2245  cout << "Outer Stereo Series " << loc_j << ":" << endl;
2246  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_j].size(); ++loc_k)
2247  cout << "Super Layer, Seed Index = " << locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_j][loc_k]->dSuperLayer << ", " << locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_j][loc_k]->dSeedIndex << endl;
2248  }
2249  const DHelicalFit* locFit = locCDCTrackCircle->fit;
2250  if(locFit != NULL)
2251  {
2252  cout << "Fit h, x0, y0, r0, phi = " << locFit->h << ", " << locFit->x0 << ", " << locFit->y0 << ", " << locFit->r0 << ", " << locFit->phi << endl;
2253  cout << "Fit Weighted chisq/ndf = " << locCDCTrackCircle->dWeightedChiSqPerDF << endl;
2254  cout << "Stereo Weighted chisq/ndf = " << locCDCTrackCircle->dWeightedChiSqPerDF_Stereo << endl;
2255  }
2256 }
2257 
2258 //--------------------------
2259 // Reject_DefiniteSpiralArms
2260 //--------------------------
2261 void DTrackCandidate_factory_CDC::Reject_DefiniteSpiralArms(vector<DCDCTrackCircle*>& locCDCTrackCircles)
2262 {
2263  //disregard all DCDCTrackCircle objects where the innermost super layer is definitely a spiral turn
2264  //e.g. the track has already turned backed inwards towards the target, but then turns back outward again towards the BCAL
2265  vector<DCDCTrackCircle*>::iterator locIterator;
2266  for(locIterator = locCDCTrackCircles.begin(); locIterator != locCDCTrackCircles.end();)
2267  {
2268  DCDCTrackCircle* locCDCTrackCircle = *locIterator;
2269 
2270  // get the innermost super layer seed
2271  DCDCSuperLayerSeed* locInnermostSuperLayerSeed = NULL;
2272  if(!locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
2273  locInnermostSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_Axial.front();
2274  if(!locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.empty())
2275  {
2276  DCDCSuperLayerSeed* locTempSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[0].front();
2277  if(locInnermostSuperLayerSeed == NULL)
2278  locInnermostSuperLayerSeed = locTempSuperLayerSeed;
2279  else if(locTempSuperLayerSeed->dSuperLayer < locInnermostSuperLayerSeed->dSuperLayer)
2280  locInnermostSuperLayerSeed = locTempSuperLayerSeed;
2281  }
2282  else if(!locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.empty())
2283  {
2284  DCDCSuperLayerSeed* locTempSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[0].front();
2285  if(locInnermostSuperLayerSeed == NULL)
2286  locInnermostSuperLayerSeed = locTempSuperLayerSeed;
2287  else if(locTempSuperLayerSeed->dSuperLayer < locInnermostSuperLayerSeed->dSuperLayer)
2288  locInnermostSuperLayerSeed = locTempSuperLayerSeed;
2289  }
2290  if (locInnermostSuperLayerSeed == NULL)
2291  continue; //is impossible, but clears the warning from the static analyzer
2292 
2293  //loop over spiral links, see if one of them is a definite spiral link
2294  bool locIsDefinitelyTurningFlag = false;
2295  map<int, DSpiralParams_t>::iterator locSpiralIterator;
2296  for(locSpiralIterator = locInnermostSuperLayerSeed->dSpiralLinkParams.begin(); locSpiralIterator != locInnermostSuperLayerSeed->dSpiralLinkParams.end(); ++locSpiralIterator)
2297  {
2298  if(locSpiralIterator->second.dDefiniteSpiralTurnRingFlag == 0)
2299  continue;
2300  locIsDefinitelyTurningFlag = true;
2301  break;
2302  }
2303 
2304  //if definitely a spiral turn in its innermost super layer: then delete the track circle: does not originate from the target
2305  if(locIsDefinitelyTurningFlag)
2306  {
2307  Recycle_DCDCTrackCircle(locCDCTrackCircle); //recycle
2308  locIterator = locCDCTrackCircles.erase(locIterator);
2309  }
2310  else
2311  ++locIterator;
2312  }
2313 }
2314 
2315 //----------------------
2316 // Drop_IncompleteGroups
2317 //----------------------
2318 void DTrackCandidate_factory_CDC::Drop_IncompleteGroups(vector<DCDCTrackCircle*>& locCDCTrackCircles)
2319 {
2320  // Only interested in groups that contain either:
2321  // At least super layer 1 (forward going particles)
2322  // Or at least one stereo layer and one axial layer
2323  vector<DCDCTrackCircle*>::iterator locIterator;
2324  for(locIterator = locCDCTrackCircles.begin(); locIterator != locCDCTrackCircles.end();)
2325  {
2326  DCDCTrackCircle* locCDCTrackCircle = *locIterator;
2327  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
2328  {
2329  Recycle_DCDCTrackCircle(locCDCTrackCircle); //recycle
2330  locIterator = locCDCTrackCircles.erase(locIterator); //no axial super layers
2331  continue;
2332  }
2333 
2334  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.front()->dSuperLayer == 1)
2335  {
2336  ++locIterator; //has super layer 1: group is OK
2337  continue;
2338  }
2339 
2340  if(locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.empty() && locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.empty())
2341  {
2342  Recycle_DCDCTrackCircle(locCDCTrackCircle); //recycle
2343  locIterator = locCDCTrackCircles.erase(locIterator); //no stereo super layers
2344  }
2345  else
2346  ++locIterator; //has at least one axial & one stereo super layer: group is OK
2347  }
2348 }
2349 
2350 //------------
2351 // Fit_Circles
2352 //------------
2353 void DTrackCandidate_factory_CDC::Fit_Circles(vector<DCDCTrackCircle*>& locCDCTrackCircles, bool locFitOnlyIfNullFitFlag, bool locAddStereoLayerIntersectionsFlag, bool locFitDuringLinkingFlag)
2354 {
2355  /// Do a quick fit of the 2-D projection of the axial hits in the seed to a circle
2356  /// Include intersection between stereo layer seeds if locAddStereoLayerIntersectionsFlag = true (assumes only one stereo seed series for each inner/outer)
2357  /// Determine the sign of the charge (and correspondingly the initial phi angle)
2358  /// assuming that the majority of hits come from the outgoing part of the track.
2359 
2360  /// If the resulting circle passes within MAX_HIT_DIST the majority of the hits,
2361  /// then the fit was a success. Otherwise it is a failure and the DCDCTrackCircle is discarded.
2362 
2363  /// locFitOnlyIfNullFitFlag should be false unless just truncated the input set of circles
2364  /// if true, this will skip fitting circles that have DCDCTrackCircle::fit != NULL (i.e. were not truncated)
2365 
2366  double locAxialStrawVariance = 0.214401; //[d/sqrt(12)]^2, d = 1.604 = straw diameter
2367  vector<DCDCTrackCircle*>::iterator locIterator;
2368  for(locIterator = locCDCTrackCircles.begin(); locIterator != locCDCTrackCircles.end();)
2369  {
2370  DCDCTrackCircle* locCDCTrackCircle = *locIterator;
2371  size_t locNumAxialSuperLayers = locCDCTrackCircle->dSuperLayerSeeds_Axial.size();
2372 
2373  if(locFitDuringLinkingFlag && (locNumAxialSuperLayers < 2))
2374  {
2375  //just trying to reduce number of circles during super layer linking; don't try to fit & don't reject yet
2376  ++locIterator;
2377  continue;
2378  }
2379 
2380  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
2381  {
2382  //no axial hits: cannot fit circle: reject
2383  Recycle_DCDCTrackCircle(locCDCTrackCircle); //recycle
2384  locIterator = locCDCTrackCircles.erase(locIterator);
2385  continue;
2386  }
2387 
2388  if(locFitOnlyIfNullFitFlag && (locCDCTrackCircle->fit != NULL))
2389  {
2390  ++locIterator;
2391  continue; //fit is not null: & locFitOnlyIfNullFitFlag is true: circle not truncated, don't refit
2392  }
2393 
2394  // Setup the fit (add hits)
2395  DHelicalFit* locFit = Get_Resource_HelicalFit();
2396  unsigned int locNumHitsInFit = 0;
2397  for(size_t loc_i = 0; loc_i < locNumAxialSuperLayers; ++loc_i)
2398  {
2399  vector<DCDCTrkHit*> hits;
2400  locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_i]->Get_Hits(hits);
2401  for(size_t k = 0; k < hits.size(); ++k)
2402  {
2403  if(hits[k]->flags & OUT_OF_TIME)
2404  continue;
2405  DVector3 pos = hits[k]->hit->wire->origin;
2406  locFit->AddHitXYZ(pos.x(), pos.y(), pos.z(), locAxialStrawVariance, locAxialStrawVariance, 0.0);
2407  ++locNumHitsInFit;
2408  }
2409  }
2410 
2411  //add intersections between stereo super layers if desired
2412  //only uses the first combination of stereo super layers (series)
2413  if(locAddStereoLayerIntersectionsFlag)
2414  {
2415  DCDCSuperLayerSeed* locInnerSuperLayerSeed = locCDCTrackCircle->Get_SuperLayerSeed(2);
2416  DCDCSuperLayerSeed* locOuterSuperLayerSeed = locCDCTrackCircle->Get_SuperLayerSeed(3);
2417  if((locInnerSuperLayerSeed != NULL) && (locOuterSuperLayerSeed != NULL))
2418  {
2419  // Add intersection between super layers 2 & 3
2420  DVector3 locIntersection = Find_IntersectionBetweenSuperLayers(locInnerSuperLayerSeed, locOuterSuperLayerSeed);
2421  //are these the correct uncertainties?
2422  locFit->AddHitXYZ(locIntersection.x(), locIntersection.y(), locIntersection.z(), locAxialStrawVariance, locAxialStrawVariance, 0.0);
2423  }
2424  locInnerSuperLayerSeed = locCDCTrackCircle->Get_SuperLayerSeed(5);
2425  locOuterSuperLayerSeed = locCDCTrackCircle->Get_SuperLayerSeed(6);
2426  if((locInnerSuperLayerSeed != NULL) && (locOuterSuperLayerSeed != NULL))
2427  {
2428  // Add intersection between super layers 5 & 6
2429  DVector3 locIntersection = Find_IntersectionBetweenSuperLayers(locInnerSuperLayerSeed, locOuterSuperLayerSeed);
2430  //are these the correct uncertainties?
2431  locFit->AddHitXYZ(locIntersection.x(), locIntersection.y(), locIntersection.z(), locAxialStrawVariance, locAxialStrawVariance, 0.0);
2432  }
2433  }
2434 
2435  //place a tighter constraint on the beam center if fewer hits: tracks with detached vertices may not go through the center
2436  double locBeamRMS = BeamRMS*locNumAxialSuperLayers; //1sigma = 0.5, 1.0, 1.5 //3sigma = 1.5, 3.0, 4.5
2437 
2438  // Perform the fit
2439  if(locFit->FitCircleRiemann(TARGET_Z, locBeamRMS) != NOERROR)
2440  {
2441  if(DEBUG_LEVEL > 3)
2442  cout << "Riemann fit failed. Attempting regression fit..." << endl;
2443  if(locFit->FitCircle() != NOERROR)
2444  {
2445  if(DEBUG_LEVEL > 3)
2446  cout << "Regression circle fit failed. Trying straight line." << endl;
2447  if(locFit->FitCircleStraightTrack() != NOERROR)
2448  {
2449  if(DEBUG_LEVEL > 3)
2450  cout << "Trying straight line fit failed. Giving up." << endl;
2451  Recycle_DCDCTrackCircle(locCDCTrackCircle); //recycle
2452  locIterator = locCDCTrackCircles.erase(locIterator);
2453  continue;
2454  }
2455  }
2456  else
2457  locFit->FindSenseOfRotation();
2458  }
2459  else
2460  locFit->GuessChargeFromCircleFit(); // for Riemann fit
2461 
2462  // Check if majority of hits are close to circle. Also calculate the avg drift time for the hits close to the circle.
2463  double x0 = locFit->x0;
2464  double y0 = locFit->y0;
2465  double r0 = locFit->r0;
2466  size_t locNumHitsCloseToCircle = 0;
2467  double locAverageDriftTime = 0.0;
2468  unsigned int locTotalNumHits = 0;
2469  for(size_t loc_i = 0; loc_i < locNumAxialSuperLayers; ++loc_i)
2470  {
2471  vector<DCDCTrkHit*> hits;
2472  locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_i]->Get_Hits(hits);
2473  locTotalNumHits += hits.size();
2474  for(size_t k = 0; k < hits.size(); ++k)
2475  {
2476  if(hits[k]->flags & OUT_OF_TIME)
2477  continue;
2478  double dx = hits[k]->hit->wire->origin.X() - x0;
2479  double dy = hits[k]->hit->wire->origin.Y() - y0;
2480  double d = sqrt(dx*dx + dy*dy);
2481  if(DEBUG_LEVEL > 15)
2482  cout << "dist = " << d - r0 << endl;
2483  if(fabs(d - r0) > MAX_HIT_DIST)
2484  continue;
2485  ++locNumHitsCloseToCircle;
2486  locAverageDriftTime += hits[k]->hit->tdrift;
2487  }
2488  }
2489  locAverageDriftTime /= ((double)locNumHitsCloseToCircle);
2490 
2491  if(DEBUG_LEVEL > 3)
2492  cout << "Circle fit: Nhits=" << locFit->GetNhits() << " h=" << locFit->h << " N=" << locNumHitsCloseToCircle << " phi=" << locFit->phi << endl;
2493  if(locNumHitsCloseToCircle < MIN_SEED_HITS)
2494  {
2495  if(DEBUG_LEVEL > 3)
2496  cout << "Rejected circle fit due to too few hits on track (N=" << locNumHitsCloseToCircle << " MIN_SEED_HITS=" << MIN_SEED_HITS << ")" << endl;
2497  Recycle_DCDCTrackCircle(locCDCTrackCircle); //recycle
2498  locIterator = locCDCTrackCircles.erase(locIterator);
2499  continue;
2500  }
2501 
2502  if(locNumHitsCloseToCircle < locTotalNumHits/2)
2503  {
2504  if(DEBUG_LEVEL > 3)
2505  cout << "Rejected circle fit due to minority of hits on track (N=" << locNumHitsCloseToCircle << " locTotalNumHits/2=" << locTotalNumHits/2 << ")" << endl;
2506  Recycle_DCDCTrackCircle(locCDCTrackCircle); //recycle
2507  locIterator = locCDCTrackCircles.erase(locIterator);
2508  continue;
2509  }
2510 
2511  // Fit is good, save fit results
2512  locCDCTrackCircle->fit = locFit;
2513  double locWeightedChiSqPerDF = ((fabs(locFit->chisq) > 0.0) && (locFit->ndof > 0)) ? locFit->chisq/(float(locFit->ndof*locNumAxialSuperLayers*locNumAxialSuperLayers)) : 9.9E50;
2514  if(DEBUG_LEVEL > 10)
2515  cout << "chisq, ndof, numaxial, weightedchisq = " << locFit->chisq << ", " << locFit->ndof << ", " << locNumAxialSuperLayers << ", " << locWeightedChiSqPerDF << endl;
2516  locCDCTrackCircle->dWeightedChiSqPerDF = locWeightedChiSqPerDF;
2517  locCDCTrackCircle->dAverageDriftTime = locAverageDriftTime;
2518 
2519  ++locIterator;
2520  }
2521 }
2522 
2523 //------------------------------------
2524 // Find_IntersectionBetweenSuperLayers
2525 //------------------------------------
2527 {
2528  const DCDCRingSeed& locInnerSuperLayerRing = locInnerSuperLayerSeed->dCDCRingSeeds.back(); //last ring of inner super layer
2529  const DCDCRingSeed& locOuterSuperLayerRing = locOuterSuperLayerSeed->dCDCRingSeeds.front(); //first ring of outer super layer
2530 
2531  const DCDCWire* first_wire = locInnerSuperLayerRing.hits.front()->hit->wire;
2532  const DCDCWire* second_wire = locOuterSuperLayerRing.hits.front()->hit->wire;
2533 
2534  DVector3 u0=first_wire->origin;
2535  DVector3 udir=first_wire->udir;
2536  DVector3 v0=second_wire->origin;
2537  DVector3 vdir=second_wire->udir;
2538  DVector3 diff=u0-v0;
2539  double u_dot_v=udir.Dot(vdir);
2540  double u_dot_diff=udir.Dot(diff);
2541  double v_dot_diff=vdir.Dot(diff);
2542  double scale=1./(1.-u_dot_v*u_dot_v);
2543  double ul=scale*(u_dot_v*v_dot_diff-u_dot_diff);
2544  double vl=scale*(v_dot_diff-u_dot_v*u_dot_diff);
2545  DVector3 pos=0.5*(u0+ul*udir+v0+vl*vdir);
2546 
2547  if(DEBUG_LEVEL > 10)
2548  cout << "XYZ intersection between SL" << locInnerSuperLayerSeed->dSuperLayer << " and SL" << locOuterSuperLayerSeed->dSuperLayer << ": " << pos.X() << ", " << pos.Y() << ", " << pos.Z() << endl;
2549  return pos;
2550 }
2551 
2552 /*********************************************************************************************************************************************************************/
2553 /*************************************************************** Filter Track Circles and Stereo Wires ***************************************************************/
2554 /*********************************************************************************************************************************************************************/
2555 
2556 //-----------------------
2557 // Handle_StereoAndFilter
2558 //-----------------------
2559 void DTrackCandidate_factory_CDC::Handle_StereoAndFilter(vector<DCDCTrackCircle*>& locCDCTrackCircles, bool locFinalPassFlag)
2560 {
2561  // If not on final (refinement) pass: First (potentially) truncate and then filter track circles based on track circle fit results
2562  if(!locFinalPassFlag)
2563  {
2564  Truncate_TrackCircles(locCDCTrackCircles);
2565  Set_HitBitPattern_Axial(locCDCTrackCircles);
2566  Filter_TrackCircles_Axial(locCDCTrackCircles);
2567  if(DEBUG_LEVEL > 5)
2568  {
2569  cout << "post filter clone seeds" << endl;
2570  Print_TrackCircles(locCDCTrackCircles);
2571  }
2572  }
2573 
2574  // Create new stereo super layer seeds and select the best ones.
2575  //This is done one track at a time to prevent memory spikes (memory is recycled as "new" stereo hits are rejected)
2576  vector<DCDCTrackCircle*>::iterator locIterator;
2577  size_t locCircleCounter = 0;
2578  for(locIterator = locCDCTrackCircles.begin(); locIterator != locCDCTrackCircles.end();)
2579  {
2580  if(DEBUG_LEVEL > 5)
2581  cout << "Create new Super Layer Seeds for Track Circle " << locCircleCounter << endl;
2582  // Create new super layer seeds: find the intersection between the stereo hits and the circle fit and create new seeds with that information
2583  Create_NewCDCSuperLayerSeeds(*locIterator);
2584  if(DEBUG_LEVEL > 5)
2585  cout << "Select Super Layer Seeds for Track Circle " << locCircleCounter << endl;
2586  // Select the combination of super layer seeds that give the best determination of theta/z for this track.
2587  // Rejects the track if on the final pass and no valid theta/z can be calculated.
2588  if(Select_CDCSuperLayerSeeds(*locIterator, locFinalPassFlag))
2589  ++locIterator;
2590  else
2591  {
2592  Recycle_DCDCTrackCircle(*locIterator); //recycle
2593  locIterator = locCDCTrackCircles.erase(locIterator);
2594  }
2595  ++locCircleCounter;
2596  }
2597  Set_HitBitPattern_All(locCDCTrackCircles);
2598 
2599  // If not on final (refinement) pass: Filter track circles based on stereo results
2600  if(!locFinalPassFlag)
2601  {
2602  if(DEBUG_LEVEL > 5)
2603  {
2604  cout << "stereo-selected track circles" << endl;
2605  Print_TrackCircles(locCDCTrackCircles);
2606  }
2607  // Filter out duplicates seeds and definite spiral arms.
2608  Filter_TrackCircles_Stereo(locCDCTrackCircles);
2609  if(DEBUG_LEVEL > 5)
2610  {
2611  cout << "stereo-filtered track circles" << endl;
2612  Print_TrackCircles(locCDCTrackCircles);
2613  }
2614  }
2615 }
2616 
2617 //------------------------
2618 // Set_HitBitPattern_Axial
2619 //------------------------
2620 void DTrackCandidate_factory_CDC::Set_HitBitPattern_Axial(vector<DCDCTrackCircle*>& locCDCTrackCircles)
2621 {
2622  unsigned int locNumBits = 8*sizeof(unsigned int);
2623  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
2624  {
2625  DCDCTrackCircle* locCDCTrackCircle = locCDCTrackCircles[loc_i];
2626  locCDCTrackCircle->HitBitPattern.clear();
2627  locCDCTrackCircle->HitBitPattern.resize(dNumCDCHits/(8*sizeof(unsigned int)) + 1);
2628  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_Axial.size(); ++loc_j)
2629  {
2630  vector<DCDCTrkHit*> locHits;
2631  locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_j]->Get_Hits(locHits);
2632  for(size_t loc_k = 0; loc_k < locHits.size(); ++loc_k)
2633  locCDCTrackCircle->HitBitPattern[locHits[loc_k]->index/locNumBits] |= 1 << locHits[loc_k]->index % locNumBits;
2634  }
2635  }
2636 }
2637 
2638 //----------------------
2639 // Truncate_TrackCircles
2640 //----------------------
2641 void DTrackCandidate_factory_CDC::Truncate_TrackCircles(vector<DCDCTrackCircle*>& locCDCTrackCircles)
2642 {
2643  if(locCDCTrackCircles.empty())
2644  return;
2645 
2646  // This routine is designed to save tracks that exit the drift chamber early (e.g. before SL7) when there are other tracks nearby (in phi)
2647  // The problem is when these tracks get mixed together, the track that goes most-radially-outward in the CDC generally wins
2648  // e.g. A track not reaching SL7 can match to the other track's SL7, so its fit is worse than it should be
2649  // And, if the two tracks share many hits (such as SL7), then the track not hitting SL7 tends to get rejected
2650 
2651  // It should almost be impossible for two tracks to have identical DCDCSuperLayerSeed's AND for all hits to belong to both tracks.
2652  // Two crossing tracks should almost always have different DCDCSuperLayerSeed's that share hits between them.
2653  // If the DCDCSuperLayerSeed truly ought to belong to both tracks, stripping hits won't kill the track anyway: it should still be reconstructable
2654 
2655  // To save these tracks, look for pairs of tracks that have identical axial DCDCSuperLayerSeed's: first in super layer 7
2656  // If the seeds in SL7 are identical, strip SL6 & SL7 from the track with the worse circle-fit weighted chisq/ndf.
2657  // If the seeds in SL4 are also identical in this pair, strip everything but SL1 & SL2 from the track with the worse circle-fit weighted chisq/ndf and refit it.
2658  // If the axial super layer seeds in the truncated circle are not unique, merge it with the other existing DCDCTrackCircle
2659  // If this truncated DCDCTrackCircle is merely a subset of a different DCDCTrackCircle, delete it.
2660  // Refit the newly-truncated track circles.
2661 
2662  // Next look for pairs of tracks that have identical DCDCSuperLayerSeed's in super layer 4
2663  // If the track with the worse circle-fit weighted chisq/ndf has an SL7, DO NOT truncate it (it is a unique SL7 (else would have been rejected earlier))
2664  // Otherwise, if the seeds in SL4 are identical, strip SL3+ from the track with the worse circle-fit weighted chisq/ndf and refit it.
2665  // If the axial super layer seeds in the truncated circle are not unique, merge it with the other existing DCDCTrackCircle
2666  // If this truncated DCDCTrackCircle is merely a subset of a different DCDCTrackCircle, delete it.
2667  // Refit the newly-truncated track circles.
2668 
2669  //first initialize "DCDCTrackCircle::dHasNonTruncatedSeedsFlag" variables
2670  //these are useful for determining whether or not any of the stereo seeds in the track circle are unique, or whether they all came from a truncation
2671  //this is necessary because after truncating a circle, it may have the same axial super layers as another track circle, with which it will be merged.
2672  //You need to know if any of the stereo combinations in a track circle are unique when determining whether the truncation result is merely a subset of another track
2673  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
2674  {
2675  if(!locCDCTrackCircles[loc_i]->dSuperLayerSeeds_InnerStereo.empty())
2676  locCDCTrackCircles[loc_i]->dHasNonTruncatedSeedsFlag_InnerStereo = true;
2677  if(!locCDCTrackCircles[loc_i]->dSuperLayerSeeds_OuterStereo.empty())
2678  locCDCTrackCircles[loc_i]->dHasNonTruncatedSeedsFlag_OuterStereo = true;
2679  else if(locCDCTrackCircles[loc_i]->Get_LastSuperLayerSeed()->dSuperLayer > 4)
2680  locCDCTrackCircles[loc_i]->dHasNonTruncatedSeedsFlag_OuterStereo = true; //e.g. SL4 is missing, so outers are grouped with inners
2681  }
2682 
2683  //assumes input circles are sorted, with largest chisq/ndf first and smallest last
2684  //want to compare the worst fit to the best fit
2685  vector<DCDCTrackCircle*>::iterator locIterator_Validating, locIterator_ToCompareTo;
2686 
2687  // FIRST CHECK FOR SAME SUPER LAYER SEED IN SL7
2688  bool locTruncationPerformedFlag = false;
2689  for(locIterator_Validating = locCDCTrackCircles.begin(); locIterator_Validating != locCDCTrackCircles.end(); ++locIterator_Validating)
2690  {
2691  DCDCTrackCircle* locCDCTrackCircle_Validating = *locIterator_Validating; //this has the worst circle-fit weighted chisq/ndf (and decreasing)
2692  if(DEBUG_LEVEL > 10)
2693  {
2694  cout << "validating: search for SL7 truncation for circle with axial seeds:" << endl;
2695  for(size_t loc_j = 0; loc_j < locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial.size(); ++loc_j)
2696  cout << "Axial Super Layer, Seed Index = " << locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial[loc_j]->dSuperLayer << ", " << locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial[loc_j]->dSeedIndex << endl;
2697  }
2698 
2699  DCDCSuperLayerSeed* locSuperLayerSeed_Validating = locCDCTrackCircle_Validating->Get_SuperLayerSeed(7);
2700  if(locSuperLayerSeed_Validating == NULL)
2701  continue; //this track circle has no SL7
2702 
2703  for(locIterator_ToCompareTo = --(locCDCTrackCircles.end()); locIterator_ToCompareTo != locIterator_Validating; --locIterator_ToCompareTo)
2704  {
2705  DCDCTrackCircle* locCDCTrackCircle_ToCompareTo = *locIterator_ToCompareTo; //this has the best circle-fit weighted chisq/ndf (and increasing)
2706  if(DEBUG_LEVEL > 10)
2707  {
2708  cout << "to-compare-to: search for SL7 truncation for circle with axial seeds:" << endl;
2709  for(size_t loc_j = 0; loc_j < locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial.size(); ++loc_j)
2710  cout << "Axial Super Layer, Seed Index = " << locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial[loc_j]->dSuperLayer << ", " << locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial[loc_j]->dSeedIndex << endl;
2711  }
2712 
2713  DCDCSuperLayerSeed* locSuperLayerSeed_ToCompareTo = locCDCTrackCircle_ToCompareTo->Get_SuperLayerSeed(7);
2714  if(locSuperLayerSeed_Validating != locSuperLayerSeed_ToCompareTo)
2715  continue; //different seed for SL7
2716 
2717  //track circles have identical seeds in SL7: should almost never be possible for both to be good tracks AND for all of the hits to belong to both
2718  // if two tracks are crossing they should almost always have different super layer seeds (that share hits)
2719  // if they are somehow both good tracks, stripping hits won't be the end of the world: track should still be reconstructable with a subset of them
2720 
2721  //check to see if SL4 is identical also
2722  locSuperLayerSeed_Validating = locCDCTrackCircle_Validating->Get_SuperLayerSeed(4);
2723  locSuperLayerSeed_ToCompareTo = locCDCTrackCircle_ToCompareTo->Get_SuperLayerSeed(4);
2724  if(locSuperLayerSeed_Validating == locSuperLayerSeed_ToCompareTo)
2725  {
2726  // SL4 is identical (or missing from both): strip everything from (and including) SL3 and outwards from the track with lower chisq/ndf
2727  //don't trust SL3 since it led to SL4: hit selector can (in theory) pick up the hits later if needed
2728  //impossible for SL1 to also be identical: would be same object because all axials would be the same
2729  if(DEBUG_LEVEL > 5)
2730  cout << "SL7's and SL4's identical: truncate to SL2" << endl;
2731  locCDCTrackCircle_Validating->Truncate_Circle(2); //2: new last super layer
2732  if(DEBUG_LEVEL > 20)
2733  {
2734  cout << "post truncate" << endl;
2735  Print_TrackCircle(locCDCTrackCircle_Validating);
2736  }
2737  }
2738  else
2739  {
2740  // SL4 is different: strip SL6 & SL7 from the track with lower chisq/ndf
2741  //don't trust SL6 since it led to SL7: hit selector can (in theory) pick up the hits later if needed
2742  if(DEBUG_LEVEL > 5)
2743  cout << "SL7's identical (but not SL4's): truncate to SL5" << endl;
2744  locCDCTrackCircle_Validating->Truncate_Circle(5); //5: new last super layer
2745  if(DEBUG_LEVEL > 20)
2746  {
2747  cout << "post truncate" << endl;
2748  Print_TrackCircle(locCDCTrackCircle_Validating);
2749  }
2750  }
2751 
2752  //reset fit
2753  dHelicalFitPool_Available.push_back(locCDCTrackCircle_Validating->fit); //will redo the fit: recycle the memory
2754  locCDCTrackCircle_Validating->fit = NULL; //indicate need to reperform fit
2755 
2756  //update truncation sources
2757  locCDCTrackCircle_Validating->dTruncationSourceCircles.push_back(locCDCTrackCircle_ToCompareTo);
2758 
2759  locTruncationPerformedFlag = true;
2760  break; //truncation successful
2761  }
2762  }
2763 
2764  if(locTruncationPerformedFlag)
2765  {
2766  //now merge any track circles that have identical axial super layers
2767  //e.g. two tracks have SL1 & SL4 but different SL7, and their SL7's are rejected by other tracks who have the same SL7s
2768  //loop order doesn't really matter here, keeping consistent anyway
2769  for(locIterator_Validating = locCDCTrackCircles.begin(); locIterator_Validating != locCDCTrackCircles.end();)
2770  {
2771  DCDCTrackCircle* locCDCTrackCircle_Validating = *locIterator_Validating;
2772  bool locMergedTrackCircleFlag = false;
2773  for(locIterator_ToCompareTo = --(locCDCTrackCircles.end()); locIterator_ToCompareTo != locIterator_Validating; --locIterator_ToCompareTo)
2774  {
2775  DCDCTrackCircle* locCDCTrackCircle_ToCompareTo = *locIterator_ToCompareTo;
2776  if(locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial != locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial)
2777  continue; //not identical
2778  //identical axial super layers: merge track circles (absorb the "Validating" one into the "ToCompareTo" one //which is which doesn't matter)
2779  if(DEBUG_LEVEL > 20)
2780  {
2781  cout << "sl7 merging circles: validating = " << endl;
2782  Print_TrackCircle(locCDCTrackCircle_Validating);
2783  cout << "sl7 merging circles: to-compare-to = " << endl;
2784  Print_TrackCircle(locCDCTrackCircle_ToCompareTo);
2785  }
2786  locCDCTrackCircle_ToCompareTo->Absorb_TrackCircle(locCDCTrackCircle_Validating);
2787  if(DEBUG_LEVEL > 20)
2788  {
2789  cout << "sl7 merge circles: output = " << endl;
2790  Print_TrackCircle(locCDCTrackCircle_ToCompareTo);
2791  }
2792  locMergedTrackCircleFlag = true;
2793  break;
2794  }
2795  if(locMergedTrackCircleFlag)
2796  {
2797  Recycle_DCDCTrackCircle(locCDCTrackCircle_Validating); //recycle
2798  locIterator_Validating = locCDCTrackCircles.erase(locIterator_Validating);
2799  }
2800  else
2801  ++locIterator_Validating;
2802  }
2803 
2804  //now check to see if any of the newly-truncated track circles is merely a subset of a different circle (regardless of which chisq/ndf is lower)
2805  //is a subset if the axials are a subset AND the outermost stereo layers dHasNonTruncatedSeedsFlag is false
2806  //if one is a subset of another, delete it
2807  for(locIterator_Validating = locCDCTrackCircles.begin(); locIterator_Validating != locCDCTrackCircles.end();)
2808  {
2809  DCDCTrackCircle* locCDCTrackCircle_Validating = *locIterator_Validating;
2810  if(locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial.size() == 3)
2811  {
2812  ++locIterator_Validating;
2813  continue; //not going to be a subset
2814  }
2815  if(DEBUG_LEVEL > 20)
2816  {
2817  cout << "sl7 checking-for-subsets: validating = " << endl;
2818  Print_TrackCircle(locCDCTrackCircle_Validating);
2819  }
2820  bool locRejectTrackFlag = false;
2821  for(locIterator_ToCompareTo = locCDCTrackCircles.begin(); locIterator_ToCompareTo != locCDCTrackCircles.end(); ++locIterator_ToCompareTo)
2822  {
2823  if(locIterator_ToCompareTo == locIterator_Validating)
2824  continue;
2825  DCDCTrackCircle* locCDCTrackCircle_ToCompareTo = *locIterator_ToCompareTo;
2826  if(DEBUG_LEVEL > 20)
2827  {
2828  cout << "sl7 checking-for-subsets: to-compare-to = " << endl;
2829  Print_TrackCircle(locCDCTrackCircle_ToCompareTo);
2830  }
2831 
2832  if(!locCDCTrackCircle_ToCompareTo->Check_IfInputIsSubset(locCDCTrackCircle_Validating))
2833  continue; //not a subset
2834 
2835  if(DEBUG_LEVEL > 10)
2836  cout << "rejecting subset circle" << endl;
2837  locRejectTrackFlag = true; //is a subset
2838  break;
2839  }
2840  if(locRejectTrackFlag)
2841  {
2842  Recycle_DCDCTrackCircle(locCDCTrackCircle_Validating); //recycle
2843  locIterator_Validating = locCDCTrackCircles.erase(locIterator_Validating);
2844  }
2845  else
2846  ++locIterator_Validating;
2847  }
2848 
2849  //now fit the newly-truncated track circles
2850  Fit_Circles(locCDCTrackCircles, true, false); //true: fit only truncated circles //false: don't add stereo intersections
2851  stable_sort(locCDCTrackCircles.begin(), locCDCTrackCircles.end(), CDCSortByChiSqPerNDFDecreasing); //sort by fit chisq/ndf
2852  if(DEBUG_LEVEL > 5)
2853  {
2854  cout << "Post-SL7-turncation track circles" << endl;
2855  Print_TrackCircles(locCDCTrackCircles);
2856  }
2857  }
2858 
2859  // NOW CHECK FOR SAME SUPER LAYER SEED IN SL4
2860  locTruncationPerformedFlag = false;
2861  for(locIterator_Validating = locCDCTrackCircles.begin(); locIterator_Validating != locCDCTrackCircles.end();)
2862  {
2863  DCDCTrackCircle* locCDCTrackCircle_Validating = *locIterator_Validating;
2864  if(DEBUG_LEVEL > 10)
2865  {
2866  cout << "validating: search for SL4 truncation for circle with axial seeds:" << endl;
2867  for(size_t loc_j = 0; loc_j < locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial.size(); ++loc_j)
2868  cout << "Axial Super Layer, Seed Index = " << locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial[loc_j]->dSuperLayer << ", " << locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial[loc_j]->dSeedIndex << endl;
2869  }
2870 
2871  DCDCSuperLayerSeed* locSuperLayerSeed_Validating = locCDCTrackCircle_Validating->Get_SuperLayerSeed(4);
2872  if(locSuperLayerSeed_Validating == NULL)
2873  {
2874  ++locIterator_Validating;
2875  continue; //this track circle has no SL4
2876  }
2877 
2878  if(locCDCTrackCircle_Validating->Get_SuperLayerSeed(7) != NULL)
2879  {
2880  //this track circle has a unique SL7 (if not unique would have been truncated earlier): do not truncate it
2881  //rejecting SL4 from the track with the SL7 would leave an unphysical combination
2882  //this track may have a low chisq/ndf because there is a kink in the track, or maybe the eloss is large and the circle doesn't quite catch SL7 very well
2883  //if the SL7 is truly bad (e.g. slightly different from a different, true SL7), then the 50% common-hit requirement should kill it (if SL4 is indeed identical)
2884  ++locIterator_Validating;
2885  continue;
2886  }
2887 
2888  DCDCSuperLayerSeed* locSuperLayerSeed1_Validating = locCDCTrackCircle_Validating->Get_SuperLayerSeed(1);
2889  bool locRejectTrackFlag = false;
2890  for(locIterator_ToCompareTo = --(locCDCTrackCircles.end()); locIterator_ToCompareTo != locIterator_Validating; --locIterator_ToCompareTo)
2891  {
2892  DCDCTrackCircle* locCDCTrackCircle_ToCompareTo = *locIterator_ToCompareTo;
2893  if(DEBUG_LEVEL > 10)
2894  {
2895  cout << "to-compare-to: search for SL4 truncation for circle with axial seeds:" << endl;
2896  for(size_t loc_j = 0; loc_j < locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial.size(); ++loc_j)
2897  cout << "Axial Super Layer, Seed Index = " << locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial[loc_j]->dSuperLayer << ", " << locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial[loc_j]->dSeedIndex << endl;
2898  }
2899 
2900  DCDCSuperLayerSeed* locSuperLayerSeed_ToCompareTo = locCDCTrackCircle_ToCompareTo->Get_SuperLayerSeed(4);
2901  if(locSuperLayerSeed_Validating != locSuperLayerSeed_ToCompareTo)
2902  continue; //different seed for SL4
2903 
2904  //SL4 is identical, check status of SL1
2905  DCDCSuperLayerSeed* locSuperLayerSeed1_ToCompareTo = locCDCTrackCircle_ToCompareTo->Get_SuperLayerSeed(1);
2906  if(locSuperLayerSeed1_Validating == locSuperLayerSeed1_ToCompareTo)
2907  {
2908  //SL1 & SL4 are identical: only difference is that locCDCTrackCircle_ToCompareTo has SL7
2909  //locCDCTrackCircle_Validating is merely a subset of locCDCTrackCircle_ToCompareTo (which has a better chisq/ndf): reject it
2910  if(DEBUG_LEVEL > 5)
2911  cout << "SL1 and SL4 are identical, while SL7 of validating is missing: reject validating track" << endl;
2912  locRejectTrackFlag = true;
2913  break;
2914  }
2915 
2916  //track circles have identical seeds in SL4, and at least one track does not have an SL7 (although both may not):
2917  //should almost never be possible for both to be good tracks AND for all of the hits to belong to both
2918  // if two tracks are crossing they should almost always have different super layer seeds (that share hits)
2919  // if they are somehow both good tracks, stripping hits won't be the end of the world: track should still be reconstructable with a subset of them
2920 
2921  //truncate the circle //don't trust SL3 since it led to SL4: hit selector can (in theory) pick up the hits later if needed
2922  if(DEBUG_LEVEL > 5)
2923  cout << "SL4 is identical, SL1 is not, while SL7 of validating is missing: truncate to SL2" << endl;
2924  locCDCTrackCircle_Validating->Truncate_Circle(2); //2: new last super layer
2925 
2926  //reset fit if not already done
2927  if(locCDCTrackCircle_Validating->fit != NULL)
2928  {
2929  dHelicalFitPool_Available.push_back(locCDCTrackCircle_Validating->fit); //will redo the fit: recycle the memory
2930  locCDCTrackCircle_Validating->fit = NULL; //indicate need to reperform fit
2931  }
2932 
2933  //update truncation sources
2934  bool locIsAlreadyTruncationSourceFlag = false;
2935  for(size_t loc_i = 0; loc_i < locCDCTrackCircle_Validating->dTruncationSourceCircles.size(); ++loc_i)
2936  {
2937  if(locCDCTrackCircle_Validating->dTruncationSourceCircles[loc_i] != locCDCTrackCircle_ToCompareTo)
2938  continue;
2939  locIsAlreadyTruncationSourceFlag = true;
2940  break;
2941  }
2942  if(!locIsAlreadyTruncationSourceFlag)
2943  locCDCTrackCircle_Validating->dTruncationSourceCircles.push_back(locCDCTrackCircle_ToCompareTo);
2944 
2945  locTruncationPerformedFlag = true;
2946  break; //truncation successful
2947  }
2948 
2949  if(locRejectTrackFlag)
2950  {
2951  Recycle_DCDCTrackCircle(locCDCTrackCircle_Validating); //recycle
2952  locIterator_Validating = locCDCTrackCircles.erase(locIterator_Validating);
2953  }
2954  else
2955  ++locIterator_Validating;
2956  }
2957 
2958  if(locTruncationPerformedFlag)
2959  {
2960  //now merge any track circles that have identical axial super layers
2961  for(locIterator_Validating = locCDCTrackCircles.begin(); locIterator_Validating != locCDCTrackCircles.end();)
2962  {
2963  DCDCTrackCircle* locCDCTrackCircle_Validating = *locIterator_Validating;
2964  bool locMergedTrackCircleFlag = false;
2965  for(locIterator_ToCompareTo = --(locCDCTrackCircles.end()); locIterator_ToCompareTo != locIterator_Validating; --locIterator_ToCompareTo)
2966  {
2967  DCDCTrackCircle* locCDCTrackCircle_ToCompareTo = *locIterator_ToCompareTo;
2968  if(locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial != locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial)
2969  continue; //not identical
2970  //identical axial super layers: merge track circles (absorb the "Validating" one into the "ToCompareTo" one //which is which doesn't matter)
2971  locCDCTrackCircle_ToCompareTo->Absorb_TrackCircle(locCDCTrackCircle_Validating);
2972  locMergedTrackCircleFlag = true;
2973  break;
2974  }
2975  if(locMergedTrackCircleFlag)
2976  {
2977  Recycle_DCDCTrackCircle(locCDCTrackCircle_Validating); //recycle
2978  locIterator_Validating = locCDCTrackCircles.erase(locIterator_Validating);
2979  }
2980  else
2981  ++locIterator_Validating;
2982  }
2983 
2984  //now check to see if any of the newly-truncated track circles is merely a subset of a different circle (regardless of which chisq/ndf is lower)
2985  //is a subset if the axials are a subset AND the outermost stereo layers dHasNonTruncatedSeedsFlag is false
2986  //if one is a subset of another, delete it
2987  for(locIterator_Validating = locCDCTrackCircles.begin(); locIterator_Validating != locCDCTrackCircles.end();)
2988  {
2989  DCDCTrackCircle* locCDCTrackCircle_Validating = *locIterator_Validating;
2990  bool locRejectTrackFlag = false;
2991  if(DEBUG_LEVEL > 20)
2992  {
2993  cout << "sl4 checking-for-subsets: validating = " << endl;
2994  Print_TrackCircle(locCDCTrackCircle_Validating);
2995  }
2996  for(locIterator_ToCompareTo = locCDCTrackCircles.begin(); locIterator_ToCompareTo != locCDCTrackCircles.end(); ++locIterator_ToCompareTo)
2997  {
2998  if(locIterator_ToCompareTo == locIterator_Validating)
2999  continue;
3000  DCDCTrackCircle* locCDCTrackCircle_ToCompareTo = *locIterator_ToCompareTo;
3001  if(DEBUG_LEVEL > 20)
3002  {
3003  cout << "sl4 checking-for-subsets: to-compare-to = " << endl;
3004  Print_TrackCircle(locCDCTrackCircle_ToCompareTo);
3005  }
3006 
3007  if(!locCDCTrackCircle_ToCompareTo->Check_IfInputIsSubset(locCDCTrackCircle_Validating))
3008  continue; //not a subset
3009 
3010  locRejectTrackFlag = true; //is a subset
3011  if(DEBUG_LEVEL > 10)
3012  cout << "rejecting subset circle" << endl;
3013  break;
3014  }
3015  if(locRejectTrackFlag)
3016  {
3017  Recycle_DCDCTrackCircle(locCDCTrackCircle_Validating); //recycle
3018  locIterator_Validating = locCDCTrackCircles.erase(locIterator_Validating);
3019  }
3020  else
3021  ++locIterator_Validating;
3022  }
3023 
3024  //now fit the newly-truncated track circles
3025  Fit_Circles(locCDCTrackCircles, true, false); //true: fit only truncated circles //false: don't add stereo intersections
3026  stable_sort(locCDCTrackCircles.begin(), locCDCTrackCircles.end(), CDCSortByChiSqPerNDFDecreasing); //sort by fit chisq/ndf
3027  if(DEBUG_LEVEL > 5)
3028  {
3029  cout << "Post-SL4-turncation track circles" << endl;
3030  Print_TrackCircles(locCDCTrackCircles);
3031  }
3032  }
3033 }
3034 
3035 //--------------------------
3036 // Filter_TrackCircles_Axial
3037 //--------------------------
3038 void DTrackCandidate_factory_CDC::Filter_TrackCircles_Axial(vector<DCDCTrackCircle*>& locCDCTrackCircles)
3039 {
3040  if(locCDCTrackCircles.empty())
3041  return;
3042 
3043  //assumes input circles are sorted, with largest chisq/ndf first and smallest last
3044  //want to compare the worst fit to the best fit
3045  vector<DCDCTrackCircle*>::iterator locIterator_Validating, locIterator_ToCompareTo;
3046 
3047  //FIRST: If circles share > MAX_COMMON_HIT_FRACTION of axial hits, reject circle with larger chisq/ndf
3048  for(locIterator_Validating = locCDCTrackCircles.begin(); locIterator_Validating != locCDCTrackCircles.end();)
3049  {
3050  DCDCTrackCircle* locCDCTrackCircle_Validating = *locIterator_Validating;
3051  if(locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial.empty())
3052  continue; //no axial hits to share (somehow)
3053 
3054  size_t locNumHits_Validating = 0;
3055  vector<DCDCTrkHit*> hits;
3056  for(size_t loc_i = 0; loc_i < locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial.size(); ++loc_i)
3057  {
3058  locCDCTrackCircle_Validating->dSuperLayerSeeds_Axial[loc_i]->Get_Hits(hits);
3059  locNumHits_Validating += hits.size();
3060  }
3061 
3062  bool locRejectTrackCircleFlag = false;
3063  for(locIterator_ToCompareTo = --(locCDCTrackCircles.end()); locIterator_ToCompareTo != locIterator_Validating; --locIterator_ToCompareTo)
3064  {
3065  DCDCTrackCircle* locCDCTrackCircle_ToCompareTo = *locIterator_ToCompareTo;
3066  if(locCDCTrackCircle_ToCompareTo->dSuperLayerSeeds_Axial.empty())
3067  continue; //no axial hits to share (somehow)
3068 
3069  //If seeds share > MAX_COMMON_HIT_FRACTION of hits, reject seed with larger chisq/ndf
3070  size_t locNumCommonHits = 0;
3071  size_t locNumWords = locCDCTrackCircle_Validating->HitBitPattern.size();
3072  for(size_t loc_i = 0; loc_i < locNumWords; ++loc_i)
3073  locNumCommonHits += bitcount(locCDCTrackCircle_Validating->HitBitPattern[loc_i] & locCDCTrackCircle_ToCompareTo->HitBitPattern[loc_i]);
3074  double locHitFraction = double(locNumCommonHits)/double(locNumHits_Validating);
3075 
3076  if(locHitFraction > MAX_COMMON_HIT_FRACTION)
3077  {
3078  locRejectTrackCircleFlag = true;
3079  break;
3080  }
3081  }
3082  if(locRejectTrackCircleFlag)
3083  {
3084  //free up some memory by clearing the seed vectors via reset
3085  Recycle_DCDCTrackCircle(locCDCTrackCircle_Validating); //recycle
3086  locIterator_Validating = locCDCTrackCircles.erase(locIterator_Validating);
3087  }
3088  else
3089  ++locIterator_Validating; //track circle is valid (for now)
3090  }
3091 }
3092 
3093 //-----------------------------
3094 // Create_NewCDCSuperLayerSeeds
3095 //-----------------------------
3097 {
3098  // Create new stereo DCDCSuperLayerSeed objects, finding the intersections of each stereo wire with the fit circle
3099 
3100  map<DCDCSuperLayerSeed*, DCDCSuperLayerSeed*> locConvertedSuperLayerSeeds;
3101  map<DCDCSuperLayerSeed*, DCDCSuperLayerSeed*>::iterator locMapIterator; //map from orig super layer to new super layer
3102  map<DCDCTrkHit*, DCDCTrkHit*> locProjectedStereoHitMap; //map from orig (super layer, non-circle-projected) stereo hit to circle-projected (hit-z-group) hit
3103 
3104  //inner stereo
3105  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.size(); ++loc_i)
3106  {
3107  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i].size(); ++loc_j)
3108  {
3109  DCDCSuperLayerSeed* locCDCSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i][loc_j];
3110  locMapIterator = locConvertedSuperLayerSeeds.find(locCDCSuperLayerSeed);
3111  if(locMapIterator != locConvertedSuperLayerSeeds.end())
3112  {
3113  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i][loc_j] = locMapIterator->second;
3114  continue; //already converted
3115  }
3116  DCDCSuperLayerSeed* locNewCDCSuperLayerSeed = Create_NewStereoSuperLayerSeed(locCDCSuperLayerSeed, locCDCTrackCircle, locProjectedStereoHitMap);
3117  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i][loc_j] = locNewCDCSuperLayerSeed;
3118  locConvertedSuperLayerSeeds[locCDCSuperLayerSeed] = locNewCDCSuperLayerSeed;
3119  }
3120  }
3121 
3122  //outer stereo
3123  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.size(); ++loc_i)
3124  {
3125  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_i].size(); ++loc_j)
3126  {
3127  DCDCSuperLayerSeed* locCDCSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_i][loc_j];
3128  locMapIterator = locConvertedSuperLayerSeeds.find(locCDCSuperLayerSeed);
3129  if(locMapIterator != locConvertedSuperLayerSeeds.end())
3130  {
3131  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_i][loc_j] = locMapIterator->second;
3132  continue; //already converted
3133  }
3134  DCDCSuperLayerSeed* locNewCDCSuperLayerSeed = Create_NewStereoSuperLayerSeed(locCDCSuperLayerSeed, locCDCTrackCircle, locProjectedStereoHitMap);
3135  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_i][loc_j] = locNewCDCSuperLayerSeed;
3136  locConvertedSuperLayerSeeds[locCDCSuperLayerSeed] = locNewCDCSuperLayerSeed;
3137  }
3138  }
3139 }
3140 
3141 //-------------------------------
3142 // Create_NewStereoSuperLayerSeed
3143 //-------------------------------
3144 DTrackCandidate_factory_CDC::DCDCSuperLayerSeed* DTrackCandidate_factory_CDC::Create_NewStereoSuperLayerSeed(DCDCSuperLayerSeed* locCDCSuperLayerSeed, const DCDCTrackCircle* locCDCTrackCircle, map<DCDCTrkHit*, DCDCTrkHit*>& locProjectedStereoHitMap)
3145 {
3146  //locProjectedStereoHitMap is map from orig (super layer, non-circle-projected) stereo hit to circle-projected hit
3147  DCDCSuperLayerSeed* locNewCDCSuperLayerSeed = Get_Resource_CDCSuperLayerSeed();
3148  *locNewCDCSuperLayerSeed = *locCDCSuperLayerSeed;
3149 
3150  // Project all stereo hits in this super layer onto the circle fit
3151 
3152  for(size_t loc_i = 0; loc_i < locCDCSuperLayerSeed->dCDCRingSeeds.size(); ++loc_i)
3153  {
3154  vector<DCDCTrkHit*>& hits = locCDCSuperLayerSeed->dCDCRingSeeds[loc_i].hits;
3155  vector<DCDCTrkHit*> locProjectedHits;
3156  for(size_t loc_l = 0; loc_l < hits.size(); ++loc_l)
3157  {
3158  if(fabs(hits[loc_l]->hit->tdrift - locCDCTrackCircle->dAverageDriftTime) > MAX_SEED_TIME_DIFF)
3159  continue; // Ignore hits that are out of time with the group
3160 
3161  // If haven't done so already, Calculate intersection points between circle and stereo wire
3162  DCDCTrkHit* locProjectedCDCTrkHit = NULL;
3163  map<DCDCTrkHit*, DCDCTrkHit*>::iterator locHitIterator = locProjectedStereoHitMap.find(hits[loc_l]);
3164  if(locHitIterator == locProjectedStereoHitMap.end())
3165  {
3166  // Clone the hit and set it's stereo-hit-position
3167  DVector3 locStereoHitPos;
3168  double locPhiStereo = 0.0, var_z = 9.9E9;
3169  locProjectedCDCTrkHit = Get_Resource_CDCTrkHit();
3170  *locProjectedCDCTrkHit = *hits[loc_l];
3171  //if below is false: wire doesn't intersect the circle: in this case, don't reject hit outright: ignore for theta/z, but let wire-based tracking try to use it
3172  //e.g., track has a spiral turn in SL6, and since there is no SL7, the circle-fit is extrapolated into SL6 and doesn't quite catch the spiral turn
3173  if(Calc_StereoPosition(locProjectedCDCTrkHit->hit->wire, locCDCTrackCircle->fit, locStereoHitPos, var_z, locPhiStereo))
3174  locProjectedCDCTrkHit->dValidStereoHitPosFlag = true;
3175  locProjectedCDCTrkHit->dStereoHitPos = locStereoHitPos;
3176  locProjectedCDCTrkHit->var_z = var_z;
3177  locProjectedCDCTrkHit->dPhiStereo = locPhiStereo;
3178  dStereoHitNumUsedMap[locProjectedCDCTrkHit] = 1;
3179  }
3180  else
3181  {
3182  //hit was already projected onto this circle (e.g. in a different super layer seed), just reuse the results/memory
3183  locProjectedCDCTrkHit = locHitIterator->second;
3184  ++dStereoHitNumUsedMap[locProjectedCDCTrkHit];
3185  }
3186 
3187  // Save the hit
3188  locProjectedHits.push_back(locProjectedCDCTrkHit);
3189  }
3190  locNewCDCSuperLayerSeed->dCDCRingSeeds[loc_i].hits = locProjectedHits;
3191  }
3192 
3193  return locNewCDCSuperLayerSeed;
3194 }
3195 
3196 //--------------------
3197 // Calc_StereoPosition
3198 //--------------------
3199 bool DTrackCandidate_factory_CDC::Calc_StereoPosition(const DCDCWire *wire, const DHelicalFit* fit, DVector3 &pos, double &var_z, double& locPhiStereo, double d)
3200 {
3201  // Calculate intersection point between circle and stereo wire
3202  DVector3 origin = wire->origin;
3203  DVector3 dir = (1./wire->udir.z())*wire->udir;
3204  double dx = origin.x() - fit->x0;
3205  double dy = origin.y() - fit->y0;
3206  double ux = dir.x();
3207  double uy = dir.y();
3208  double temp1 = ux*ux + uy*uy;
3209  double temp2 = ux*dy - uy*dx;
3210  double b = -ux*dx - uy*dy;
3211  double dr = fit->r0 - d;
3212  double r0_sq = dr*dr;
3213  double A = r0_sq*temp1 - temp2*temp2;
3214 
3215  // Check that this wire intersects this circle
3216  if(A < 0.0)
3217  return false; // line along wire does not intersect circle, ever.
3218 
3219  // Guess for variance for z: assume straw cell size??
3220  double temp = 1.6/sin(wire->stereo);
3221  var_z = temp*temp/12.;
3222 
3223  // Calculate intersection points for the two roots
3224  double B = sqrt(A);
3225  double dz1 = (b - B)/temp1;
3226  double dz2 = (b + B)/temp1;
3227 
3228  if(DEBUG_LEVEL > 15)
3229  cout<<"dz1="<<dz1<<" dz2="<<dz2<<endl;
3230 
3231  // At this point we must decide which value of alpha to use.
3232  // For now, we just use the value closest to zero (i.e. closest to
3233  // the center of the wire).
3234  double dz = dz1;
3235  if(fabs(dz2) < fabs(dz1))
3236  dz = dz2;
3237 
3238  // Compute the position for this hit
3239  pos = origin + dz*dir;
3240 
3241  // distance along wire relative to origin
3242  double s = dz/cos(wire->stereo);
3243 
3244  if(DEBUG_LEVEL > 15)
3245  cout<<"s="<<s<<" ring="<<wire->ring<<" straw="<<wire->straw<<" stereo="<<wire->stereo<<endl;
3246 
3247  // Compute phi for the stereo wire
3248  DVector2 R(fit->x0, fit->y0);
3249  locPhiStereo = atan2(pos.Y() - R.Y(), pos.X() - R.X());
3250  R *= -1.0; // make R point from center of circle to beamline instead of other way around
3251  locPhiStereo -= R.Phi(); // make angle relative to beamline
3252 
3253  // We want this to go either from 0 to +2pi for positive charge, or 0 to -2pi for negative.
3254  double phi_hi = fit->h > 0.0 ? +M_TWO_PI : 0.0;
3255  double phi_lo = fit->h > 0.0 ? 0.0 : -M_TWO_PI;
3256  while(locPhiStereo < phi_lo)
3257  locPhiStereo += M_TWO_PI;
3258  while(locPhiStereo > phi_hi)
3259  locPhiStereo -= M_TWO_PI;
3260 
3261  return true;
3262 }
3263 
3264 //--------------------------
3265 // Select_CDCSuperLayerSeeds
3266 //--------------------------
3267 bool DTrackCandidate_factory_CDC::Select_CDCSuperLayerSeeds(DCDCTrackCircle* locCDCTrackCircle, bool locFinalPassFlag)
3268 {
3269  // If on initial pass (locFinalPassFlag = false):
3270  // Calculates the theta/z of the track for each possible combination of stereo super layer seeds.
3271  // The combination with the smallest chisq/ndf is selected, and the rest of the super layer seeds are deleted.
3272  // If there are no stereo hits, DO NOT reject the track, as Add_UnusedHits hasn't been called yet, and may find some.
3273 
3274  // If on final pass (locFinalPassFlag = true):
3275  // Calculate the theta/z of the track using a subset of the remaining stereo hits
3276  // A subset is used to give the best-possible calculation of theta/z by ignoring hits where the circle-fit may be inaccurate
3277  // This is because the projection of the stereo hits onto the circle may be bad in this region, giving a bad theta/z result
3278  // If there are no stereo hits, reject the track.
3279 
3280  // Select the best combinations of stereo hits and determine theta/z
3281  double locBestTheta = 0.0, locBestZ = TARGET_Z, locBestChiSqPerNDF = 9.9E99;
3282  vector<DCDCSuperLayerSeed*> locBestSuperLayerSeeds_Inner;
3283  vector<DCDCSuperLayerSeed*> locBestSuperLayerSeeds_Outer;
3284  bool locGoodStereoComboFoundFlag = false;
3285 
3286  if((!locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.empty()) && (!locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.empty()))
3287  {
3288  //hits in both the inner & outer stereo super layers
3289  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.size(); ++loc_i)
3290  {
3291  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.size(); ++loc_j)
3292  {
3293  //get the hits from this inner combination
3294  vector<DCDCTrkHit*> locComboHits;
3295  Select_ThetaZStereoHits(locCDCTrackCircle, loc_i, loc_j, locFinalPassFlag, locComboHits);
3296 
3297  //Evaluate theta & z for this combination, returning the chisq/ndf from the fit
3298  double locTheta = 0.0, locZ = TARGET_Z, locChiSqPerNDF = 9.9E50;
3299  if(DEBUG_LEVEL > 5)
3300  cout << "in/out try theta/z, num stereo hits = " << locComboHits.size() << endl;
3301  if(!Find_ThetaZ(locCDCTrackCircle->fit, locComboHits, locTheta, locZ, locChiSqPerNDF))
3302  continue; //combo didn't work for some reason, try a different one
3303  if(!((locChiSqPerNDF < 1.0) || (locChiSqPerNDF > -1.0)))
3304  continue; // NaN
3305  locGoodStereoComboFoundFlag = true;
3306  if(DEBUG_LEVEL > 5)
3307  cout << "in/out good theta/z: theta, z, chisq, best-chisq = " << locTheta << ", " << locZ << ", " << locChiSqPerNDF << ", " << locBestChiSqPerNDF << endl;
3308  if(locChiSqPerNDF >= locBestChiSqPerNDF)
3309  continue;
3310  // This is the best combination of stereo seeds so far, save the results
3311  locBestSuperLayerSeeds_Inner.clear();
3312  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i].size(); ++loc_k)
3313  locBestSuperLayerSeeds_Inner.push_back(locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i][loc_k]);
3314  locBestSuperLayerSeeds_Outer.clear();
3315  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_j].size(); ++loc_k)
3316  locBestSuperLayerSeeds_Outer.push_back(locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_j][loc_k]);
3317  locBestTheta = locTheta;
3318  locBestZ = locZ;
3319  locBestChiSqPerNDF = locChiSqPerNDF;
3320  }
3321  }
3322  }
3323  else if(!locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.empty())
3324  {
3325  //no hits in the outer super layers (or super layer 4 was missing)
3326  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.size(); ++loc_i)
3327  {
3328  //get the hits from this inner combination
3329  vector<DCDCTrkHit*> locComboHits;
3330  Select_ThetaZStereoHits(locCDCTrackCircle, loc_i, -1, locFinalPassFlag, locComboHits);
3331 
3332  //Evaluate theta & z for this combination, returning the chisq/ndf from the fit
3333  double locTheta = 0.0, locZ = TARGET_Z, locChiSqPerNDF = 9.9E50;
3334  if(DEBUG_LEVEL > 5)
3335  cout << "in-only try theta/z, num stereo hits = " << locComboHits.size() << endl;
3336  if(!Find_ThetaZ(locCDCTrackCircle->fit, locComboHits, locTheta, locZ, locChiSqPerNDF))
3337  continue; //combo didn't work for some reason, try a different one
3338  if(!((locChiSqPerNDF < 1.0) || (locChiSqPerNDF > -1.0)))
3339  continue; // NaN
3340  locGoodStereoComboFoundFlag = true;
3341  if(DEBUG_LEVEL > 5)
3342  cout << "in-only good theta/z: theta, z, chisq, best-chisq = " << locTheta << ", " << locZ << ", " << locChiSqPerNDF << ", " << locBestChiSqPerNDF << endl;
3343  if(locChiSqPerNDF >= locBestChiSqPerNDF)
3344  continue;
3345  // This is the best combination of stereo seeds so far, save the results
3346  locBestSuperLayerSeeds_Inner.clear();
3347  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i].size(); ++loc_k)
3348  locBestSuperLayerSeeds_Inner.push_back(locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i][loc_k]);
3349  locBestSuperLayerSeeds_Outer.clear();
3350  locBestTheta = locTheta;
3351  locBestZ = locZ;
3352  locBestChiSqPerNDF = locChiSqPerNDF;
3353  }
3354  }
3355  else if(!locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.empty())
3356  {
3357  // no hits in the inner super layers: e.g. decay product (e.g. p) of a long-lived decaying neutral particle (e.g. lambda)
3358  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.size(); ++loc_j)
3359  {
3360  //get the hits from this inner combination
3361  vector<DCDCTrkHit*> locComboHits;
3362  Select_ThetaZStereoHits(locCDCTrackCircle, -1, loc_j, locFinalPassFlag, locComboHits);
3363 
3364  //Evaluate theta & z for this combination, returning the chisq/ndf from the fit
3365  double locTheta = 0.0, locZ = TARGET_Z, locChiSqPerNDF = 9.9E50;
3366  if(DEBUG_LEVEL > 5)
3367  cout << "out-only try theta/z, num stereo hits = " << locComboHits.size() << endl;
3368  if(!Find_ThetaZ(locCDCTrackCircle->fit, locComboHits, locTheta, locZ, locChiSqPerNDF))
3369  continue; //combo didn't work for some reason, try a different one
3370  if(!((locChiSqPerNDF < 1.0) || (locChiSqPerNDF > -1.0)))
3371  continue; // NaN
3372  locGoodStereoComboFoundFlag = true;
3373  if(DEBUG_LEVEL > 5)
3374  cout << "out-only good theta/z: theta, z, chisq, best-chisq = " << locTheta << ", " << locZ << ", " << locChiSqPerNDF << ", " << locBestChiSqPerNDF << endl;
3375  if(locChiSqPerNDF >= locBestChiSqPerNDF)
3376  continue;
3377  // This is the best combination of stereo seeds so far, save the results
3378  locBestSuperLayerSeeds_Inner.clear();
3379  locBestSuperLayerSeeds_Outer.clear();
3380  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_j].size(); ++loc_k)
3381  locBestSuperLayerSeeds_Outer.push_back(locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_j][loc_k]);
3382  locBestTheta = locTheta;
3383  locBestZ = locZ;
3384  locBestChiSqPerNDF = locChiSqPerNDF;
3385  }
3386  }
3387  else //no stereo hits
3388  return (!locFinalPassFlag); //return true if don't wan't to filter, false if you do
3389 
3390  //save the results to the track circle
3391  locCDCTrackCircle->dTheta = locBestTheta;
3392  locCDCTrackCircle->dVertexZ = locBestZ;
3393  double locNumStereoSuperLayers = double(locBestSuperLayerSeeds_Inner.size() + locBestSuperLayerSeeds_Outer.size());
3394  locCDCTrackCircle->dWeightedChiSqPerDF_Stereo = locBestChiSqPerNDF/(locNumStereoSuperLayers*locNumStereoSuperLayers);
3395 
3396  set<DCDCSuperLayerSeed*> locAlreadyRecycledSuperLayerSeeds; //a seed can appear in more than one combo: don't recycle the same memory more than once!!
3397 
3398  // recycle the unused super layer seeds and store only the best ones: inner
3399  if(!locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.empty())
3400  {
3401  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.size(); ++loc_i)
3402  {
3403  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i].size(); ++loc_j)
3404  {
3405  DCDCSuperLayerSeed* locCDCSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i][loc_j];
3406  if(locAlreadyRecycledSuperLayerSeeds.find(locCDCSuperLayerSeed) != locAlreadyRecycledSuperLayerSeeds.end())
3407  continue; //already recycled!
3408  bool locKeepSuperLayerSeed = false;
3409  for(size_t loc_k = 0; loc_k < locBestSuperLayerSeeds_Inner.size(); ++loc_k)
3410  {
3411  if(locBestSuperLayerSeeds_Inner[loc_k] != locCDCSuperLayerSeed)
3412  continue;
3413  locKeepSuperLayerSeed = true; //one of the best, don't recycle!!
3414  break;
3415  }
3416  if(locKeepSuperLayerSeed)
3417  continue;
3418  Recycle_DCDCSuperLayerSeed(locCDCSuperLayerSeed); //no longer in use
3419  locAlreadyRecycledSuperLayerSeeds.insert(locCDCSuperLayerSeed);
3420  }
3421  }
3422  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.clear();
3423  if(locGoodStereoComboFoundFlag)
3424  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.push_back(locBestSuperLayerSeeds_Inner);
3425  }
3426  locAlreadyRecycledSuperLayerSeeds.clear();
3427 
3428  // recycle the unused super layer seeds and store only the best ones: outer
3429  if(!locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.empty())
3430  {
3431  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.size(); ++loc_i)
3432  {
3433  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_i].size(); ++loc_j)
3434  {
3435  DCDCSuperLayerSeed* locCDCSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[loc_i][loc_j];
3436  if(locAlreadyRecycledSuperLayerSeeds.find(locCDCSuperLayerSeed) != locAlreadyRecycledSuperLayerSeeds.end())
3437  continue; //already recycled!
3438  bool locKeepSuperLayerSeed = false;
3439  for(size_t loc_k = 0; loc_k < locBestSuperLayerSeeds_Outer.size(); ++loc_k)
3440  {
3441  if(locBestSuperLayerSeeds_Outer[loc_k] != locCDCSuperLayerSeed)
3442  continue;
3443  locKeepSuperLayerSeed = true; //one of the best, don't recycle!!
3444  break;
3445  }
3446  if(locKeepSuperLayerSeed)
3447  continue;
3448  Recycle_DCDCSuperLayerSeed(locCDCSuperLayerSeed); //no longer in use
3449  locAlreadyRecycledSuperLayerSeeds.insert(locCDCSuperLayerSeed);
3450  }
3451  }
3452  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.clear();
3453  if(locGoodStereoComboFoundFlag)
3454  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.push_back(locBestSuperLayerSeeds_Outer);
3455  }
3456 
3457  return locGoodStereoComboFoundFlag;
3458 }
3459 
3460 //------------------------
3461 // Select_ThetaZStereoHits
3462 //------------------------
3463 void DTrackCandidate_factory_CDC::Select_ThetaZStereoHits(const DCDCTrackCircle* locCDCTrackCircle, int locInnerSeedSeriesIndex, int locOuterSeedSeriesIndex, bool locFinalPassFlag, vector<DCDCTrkHit*>& locComboHits)
3464 {
3465  //tracks at the edges of the CDC's phase space OFTEN fail because the circle-fit is not perfect
3466  //this causes the projected-hit-position on the circle of the stereo hits to be incorrect
3467  //which then causes the calculated theta/z to be bad, which causes the momentum magnitude to be bad
3468  //this is especially a concern for tracks without hits in Super Layer (SL) 7: e.g. spiraling tracks in SL6 or tracks leaving the CDC
3469  //this is because the circle fit is extrapolated out to SL5 & SL6 and the errors are much larger
3470  //therefore, you must be VERY careful when selecting which stereo hits to use for the final calculation of theta & z
3471  //for the initial calculation: use all stereo hits: the initial calculation is intended to select which stereo super layer seeds are best, nothing more
3472 
3473  locComboHits.clear();
3474 
3475  // Get super layer seeds for this combination
3476  vector<DCDCSuperLayerSeed*> locSuperLayerSeeds;
3477  if(locInnerSeedSeriesIndex >= 0)
3478  {
3479  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[locInnerSeedSeriesIndex].size(); ++loc_k)
3480  locSuperLayerSeeds.push_back(locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[locInnerSeedSeriesIndex][loc_k]);
3481  }
3482  if(locOuterSeedSeriesIndex >= 0)
3483  {
3484  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[locOuterSeedSeriesIndex].size(); ++loc_k)
3485  locSuperLayerSeeds.push_back(locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[locOuterSeedSeriesIndex][loc_k]);
3486  }
3487 
3488  //select initial hits: prune hits that don't intersect the circle
3489  vector<DCDCTrkHit*> locHits;
3490  map<unsigned int, vector<DCDCTrkHit*> > locHitsBySuperLayer; //key is super layer
3491  unsigned int locTotalNumStereoHits = 0;
3492  for(size_t loc_k = 0; loc_k < locSuperLayerSeeds.size(); ++loc_k)
3493  {
3494  locSuperLayerSeeds[loc_k]->Get_Hits(locHits);
3495  for(vector<DCDCTrkHit*>::iterator locIterator = locHits.begin(); locIterator != locHits.end();)
3496  {
3497  if((*locIterator)->dValidStereoHitPosFlag)
3498  ++locIterator;
3499  else
3500  locIterator = locHits.erase(locIterator);
3501  }
3502  locHitsBySuperLayer[locSuperLayerSeeds[loc_k]->dSuperLayer] = locHits;
3503  locTotalNumStereoHits += locHits.size();
3504  }
3505 
3506  // see if no more pruning is necessary
3507  // don't prune anymore if on initial pass, or if very few stereo hits
3508  if((!locFinalPassFlag) || (locTotalNumStereoHits <= MIN_PRUNED_STEREO_HITS))
3509  {
3510  // no more pruning, add hits to locComboHits and return
3511  map<unsigned int, vector<DCDCTrkHit*> >::iterator locMapIterator;
3512  for(locMapIterator = locHitsBySuperLayer.begin(); locMapIterator != locHitsBySuperLayer.end(); ++locMapIterator)
3513  locComboHits.insert(locComboHits.end(), locMapIterator->second.begin(), locMapIterator->second.end());
3514  if(DEBUG_LEVEL > 10)
3515  cout << "no more pruning, total num stereo hits = " << locTotalNumStereoHits << endl;
3516  return; //either on first pass (eval'ing which stereo seed is best), or not enough hits to prune: return
3517  }
3518 
3519  // Now, select the stereo hits whose projection onto the cirlce-fit are closest to the axial hits
3520  // the closer the stereo hits are to the axial hits, the better the estimation of theta/z will be
3521 
3522  //calc delta-phi for all remaining hits and sort them
3523  //delta-phi: between the intersection-of-the-stereo-hit-with-the-circle and the nearest axial hits
3524  vector<pair<DCDCTrkHit*, double> > locDeltaPhis;
3525  for(size_t loc_k = 0; loc_k < locSuperLayerSeeds.size(); ++loc_k)
3526  {
3527  unsigned int locSuperLayer = locSuperLayerSeeds[loc_k]->dSuperLayer;
3528  Calc_StereoHitDeltaPhis(locSuperLayer, locHitsBySuperLayer[locSuperLayer], locCDCTrackCircle, locDeltaPhis);
3529  }
3530  stable_sort(locDeltaPhis.begin(), locDeltaPhis.end(), CDCSort_DeltaPhis);
3531 
3532  if(locDeltaPhis.size() <= MIN_PRUNED_STEREO_HITS)
3533  {
3534  for(size_t loc_k = 0; loc_k < locDeltaPhis.size(); ++loc_k)
3535  locComboHits.push_back(locDeltaPhis[loc_k].first);
3536  return;
3537  }
3538 
3539  // take at least the "MIN_PRUNED_STEREO_HITS" hits with the smallest delta_phi
3540  double locMaxHitDeltaPhi = locDeltaPhis[MIN_PRUNED_STEREO_HITS - 1].second;
3541 
3542  // now, potentially expand the max-delta-phi range in certain cases:
3543  double locDeltaPhiRangeExtension = 0.0;
3544  //if first statement below is true, want all the stereo hits:
3545  //track was matched to another track circle as a spiral turn, and it turns in its last axial layer (4 or 7)
3546  //because it is turning sharply, as much info/hits as possible is needed to give an accurate theta
3547  //however, if it was turning in a stereo layer, then the sharpest part of the turn was not included in the circle fit
3548  //in this case the hit-projections onto the circle are probably way off, so only expand to pi if turning on axial layer
3549  //if second statement below is true, then the track was very unlikely to spiral, because the radius of the circle indicates it (likely) passed through the bcal
3550  //in this case, all stereo hits within a reasonable distance (10 degrees) from the track circle are probably OK.
3551  //note: expanding beyond 10-15 degrees kills candidates at theta >= 120:
3552  //these tracks leave the CDC at SL6 and sooner, and extrapolating the circle fit out to SL6 gives spurious results, so truncate the theta-search
3553  //if neither statement below is true, then the track likely spiraled in a stereo super layer:
3554  //don't trust the stereo information as much: only take stereo hits very close to the axial hits
3555 
3556  unsigned int locLastSuperLayer = locCDCTrackCircle->Get_LastSuperLayerSeed()->dSuperLayer;
3557  if(((locLastSuperLayer == 4) || (locLastSuperLayer == 7)) && (locCDCTrackCircle->dSpiralTurnRing != -1))
3558  locDeltaPhiRangeExtension = M_PI; //spiral turn on axial layer: all stereo hits good
3559  else if(locCDCTrackCircle->fit->r0 > 65.0/2.0) //BCAL is at r = ~65
3560  locDeltaPhiRangeExtension = 10.0; //unlikely to spiral, all stereo hits reasonably close are good
3561  else
3562  locDeltaPhiRangeExtension = 5.0; //likely spiraled, trust stereo information less
3563  locMaxHitDeltaPhi += locDeltaPhiRangeExtension;
3564 
3565  if(DEBUG_LEVEL > 10)
3566  cout << "prune with max delta-phi, fit circle r0 = " << locMaxHitDeltaPhi << ", " << locCDCTrackCircle->fit->r0 << endl;
3567  size_t locDeltaPhiIndex = 0;
3568  // add stereo hits to locComboHits whose projection onto the circle fit are within locMaxHitDeltaPhi of the nearest axial hit phi
3569  for(locDeltaPhiIndex = 0; locDeltaPhiIndex < locDeltaPhis.size(); ++locDeltaPhiIndex)
3570  {
3571  if(locDeltaPhis[locDeltaPhiIndex].second > locMaxHitDeltaPhi)
3572  break;
3573  locComboHits.push_back(locDeltaPhis[locDeltaPhiIndex].first);
3574  }
3575 
3576  //make sure to have at least one wire from each super layer
3577  // this is especially useful for spiral turns in SL6, where the majority of the theta-constraining information comes from SL5 and SL6
3578  // you don't want very many of these hits because they can throw you off, but having at least one really helps
3579  // this is experimental: it may not be necessary if the above locMaxHitDeltaPhi section is better fine-tuned
3580 
3581  // to keep track of which super layers need hits, delete keys from locHitsBySuperLayer map if hits from them are already selected
3582  map<unsigned int, vector<DCDCTrkHit*> >::iterator locMapIterator;
3583  for(size_t loc_i = 0; loc_i < locComboHits.size(); ++loc_i)
3584  {
3585  unsigned int locSuperLayer = (locComboHits[loc_i]->hit->wire->ring - 1)/4 + 1;
3586  locMapIterator = locHitsBySuperLayer.find(locSuperLayer);
3587  if(locMapIterator == locHitsBySuperLayer.end())
3588  continue; //already have a hit of that type
3589  locHitsBySuperLayer.erase(locMapIterator); //have a hit of this type
3590  if(locHitsBySuperLayer.empty())
3591  break;
3592  }
3593 
3594  //locHitsBySuperLayer now only contains the keys of super layers that don't have hits yet: loop over them
3595  for(locMapIterator = locHitsBySuperLayer.begin(); locMapIterator != locHitsBySuperLayer.end(); ++locMapIterator)
3596  {
3597  // search for the hit with the lowest delta-phi from this (locMapIterator->first) super layer
3598  for(size_t loc_i = locDeltaPhiIndex; loc_i < locDeltaPhis.size(); ++loc_i) //everything before locDeltaPhiIndex was already included
3599  {
3600  unsigned int locSuperLayer = (locDeltaPhis[loc_i].first->hit->wire->ring - 1)/4 + 1;
3601  if(locSuperLayer != locMapIterator->first)
3602  continue;
3603  locComboHits.push_back(locDeltaPhis[loc_i].first); //use best hit on this super layer
3604  if(DEBUG_LEVEL > 10)
3605  cout << "Add stereo hit on SL" << locSuperLayer << ": ring, straw = " << locDeltaPhis[loc_i].first->hit->wire->ring << ", " << locDeltaPhis[loc_i].first->hit->wire->straw << endl;
3606  break;
3607  }
3608  }
3609 
3610  if(DEBUG_LEVEL > 10)
3611  cout << "final #hits = " << locComboHits.size() << endl;
3612 }
3613 
3614 //------------------------
3615 // Calc_StereoHitDeltaPhis
3616 //------------------------
3617 void DTrackCandidate_factory_CDC::Calc_StereoHitDeltaPhis(unsigned int locSuperLayer, vector<DCDCTrkHit*>& locHits, const DCDCTrackCircle* locCDCTrackCircle, vector<pair<DCDCTrkHit*, double> >& locDeltaPhis)
3618 {
3619  // calc delta-phi for hits: distance from projected-stereo-hit-position to the nearest axial hits
3620  // because the circle fit is not perfect, the stereo hit position gets progessively worse the sharper the track is turning
3621  // this screws up the theta/z calculation, so just ignore the hits that are the farthest away
3622  // don't do this unless on the final pass though: even a moderately bad theta/z is (in theory) still good enough for vetoing totally wrong hit combinations
3623 
3624  if(DEBUG_LEVEL > 10)
3625  cout << "Calc_StereoHitDeltaPhis, SL = " << locSuperLayer << ", #hits = " << locHits.size() << endl;
3626 
3627  //get the axial super layer seeds nearest this seed:
3628  DCDCSuperLayerSeed* locPriorAxialSuperLayerSeed = NULL;
3629  DCDCSuperLayerSeed* locNextAxialSuperLayerSeed = NULL;
3630  for(size_t loc_k = 0; loc_k < locCDCTrackCircle->dSuperLayerSeeds_Axial.size(); ++loc_k)
3631  {
3632  if(locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_k]->dSuperLayer < locSuperLayer)
3633  locPriorAxialSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_k];
3634  else if((locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_k]->dSuperLayer > locSuperLayer) && (locNextAxialSuperLayerSeed == NULL))
3635  locNextAxialSuperLayerSeed = locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_k];
3636  }
3637 
3638  //get the rings in the axial super layer seeds nearest this stereo seed:
3639  DCDCRingSeed* locPriorAxialRingSeed = NULL;
3640  if(locPriorAxialSuperLayerSeed != NULL)
3641  {
3642  locPriorAxialRingSeed = &(locPriorAxialSuperLayerSeed->dCDCRingSeeds.back());
3643  if(DEBUG_LEVEL > 10)
3644  cout << "Prior axial ring = " << locPriorAxialRingSeed->ring << endl;
3645  }
3646  DCDCRingSeed* locNextAxialRingSeed = NULL;
3647  if(locNextAxialSuperLayerSeed != NULL)
3648  {
3649  locNextAxialRingSeed = &(locNextAxialSuperLayerSeed->dCDCRingSeeds.front());
3650  if(DEBUG_LEVEL > 10)
3651  cout << "Next axial ring = " << locNextAxialRingSeed->ring << endl;
3652  }
3653  if((locPriorAxialRingSeed == NULL) && (locNextAxialRingSeed == NULL))
3654  return; //no axial hits: shoudldn't be possible ...
3655 
3656  // calculate min-delta-phi for each hit (to the nearest axial ring seed)
3657  for(size_t loc_i = 0; loc_i < locHits.size(); ++loc_i)
3658  {
3659  vector<DCDCTrkHit*> locTempvector(1, locHits[loc_i]);
3660  double locMinDeltaPhi = M_PI;
3661  //compare to prior axial ring
3662  if(locPriorAxialRingSeed != NULL)
3663  {
3664  double locDeltaPhi = MinDeltaPhi(locPriorAxialRingSeed->hits, locTempvector);
3665  if(locDeltaPhi < locMinDeltaPhi)
3666  locMinDeltaPhi = locDeltaPhi;
3667  }
3668  //compare to next axial ring
3669  if(locNextAxialRingSeed != NULL)
3670  {
3671  double locDeltaPhi = MinDeltaPhi(locTempvector, locNextAxialRingSeed->hits);
3672  if(locDeltaPhi < locMinDeltaPhi)
3673  locMinDeltaPhi = locDeltaPhi;
3674  }
3675  locMinDeltaPhi *= 180.0/M_PI;
3676  if(DEBUG_LEVEL > 10)
3677  cout << "Ring, Straw, min delta phi = " << locHits[loc_i]->hit->wire->ring << ", " << locHits[loc_i]->hit->wire->straw << ", " << locMinDeltaPhi << endl;
3678  //store the minimum
3679  locDeltaPhis.push_back(pair<DCDCTrkHit*, double>(locHits[loc_i], locMinDeltaPhi));
3680  }
3681 }
3682 
3683 //------------
3684 // MinDeltaPhi
3685 //------------
3686 double DTrackCandidate_factory_CDC::MinDeltaPhi(const vector<DCDCTrkHit*>& locInnerSeedHits, const vector<DCDCTrkHit*>& locOuterSeedHits)
3687 {
3688  /// Returns the minimum delta-phi between the two groups of hits. Assumes all of the hits in a given set are on the same ring.
3689  /// First it checks if the two seeds overlap in phi: if so, then return 0
3690  /// Otherwise, only the first and last hits of the adjacent rings between each seed's hit list are used.
3691  /// to calculate a maximum of 4 delta-phis (minimum of 1) of which, the smallest is returned.
3692  if(locInnerSeedHits.empty() || locOuterSeedHits.empty())
3693  {
3694  cout << "Number of seed hits 0! (Ninner = " << locInnerSeedHits.size() << " ,Nouter = " << locOuterSeedHits.size() << ")" << endl;
3695  return M_PI;
3696  }
3697 
3698  DCDCTrkHit* locInnermostRingFirstStrawHit = locInnerSeedHits.front();
3699  DCDCTrkHit* locInnermostRingLastStrawHit = locInnerSeedHits.back();
3700  DCDCTrkHit* locOutermostRingFirstStrawHit = locOuterSeedHits.front();
3701  DCDCTrkHit* locOutermostRingLastStrawHit = locOuterSeedHits.back();
3702 
3703  //see if seeds overlap in phi
3704  float locInnermostRingFirstStrawPhi = locInnermostRingFirstStrawHit->hit->wire->phi;
3705  float locInnermostRingLastStrawPhi = locInnermostRingLastStrawHit->hit->wire->phi;
3706  float locOutermostRingFirstStrawPhi = locOutermostRingFirstStrawHit->hit->wire->phi;
3707  float locOutermostRingLastStrawPhi = locOutermostRingLastStrawHit->hit->wire->phi;
3708  if(DEBUG_LEVEL > 100)
3709  cout << "inner ring: ring, first/last straws & phis = " << locInnermostRingFirstStrawHit->hit->wire->ring << ", " << locInnermostRingFirstStrawHit->hit->wire->straw << ", " << locInnermostRingLastStrawHit->hit->wire->straw << ", " << locInnermostRingFirstStrawPhi << ", " << locInnermostRingLastStrawPhi << endl;
3710  if(DEBUG_LEVEL > 100)
3711  cout << "outer ring: ring, first/last straws & phis = " << locOutermostRingFirstStrawHit->hit->wire->ring << ", " << locOutermostRingFirstStrawHit->hit->wire->straw << ", " << locOutermostRingLastStrawHit->hit->wire->straw << ", " << locOutermostRingFirstStrawPhi << ", " << locOutermostRingLastStrawPhi << endl;
3712 
3713  //account for phi = 0/2pi boundary
3714  bool locInnerRingCrossesBoundaryFlag = (locInnermostRingLastStrawPhi < locInnermostRingFirstStrawPhi);
3715  bool locOuterRingCrossesBoundaryFlag = (locOutermostRingLastStrawPhi < locOutermostRingFirstStrawPhi);
3716  if(DEBUG_LEVEL > 100)
3717  cout << "in/out boundary flags = " << locInnerRingCrossesBoundaryFlag << ", " << locOuterRingCrossesBoundaryFlag << endl;
3718  if(locOuterRingCrossesBoundaryFlag)
3719  locOutermostRingLastStrawPhi += M_TWO_PI;
3720  if(locInnerRingCrossesBoundaryFlag)
3721  locInnermostRingLastStrawPhi += M_TWO_PI;
3722  if(locOuterRingCrossesBoundaryFlag & (!locInnerRingCrossesBoundaryFlag) && ((locOutermostRingLastStrawPhi - locInnermostRingLastStrawPhi) > M_PI))
3723  {
3724  locInnermostRingFirstStrawPhi += M_TWO_PI;
3725  locInnermostRingLastStrawPhi += M_TWO_PI;
3726  }
3727  if(locInnerRingCrossesBoundaryFlag & (!locOuterRingCrossesBoundaryFlag) && ((locInnermostRingLastStrawPhi - locOutermostRingLastStrawPhi) > M_PI))
3728  {
3729  locOutermostRingFirstStrawPhi += M_TWO_PI;
3730  locOutermostRingLastStrawPhi += M_TWO_PI;
3731  }
3732 
3733  if(DEBUG_LEVEL > 100)
3734  cout << "final inner ring: ring, first/last straws & phis = " << locInnermostRingFirstStrawHit->hit->wire->ring << ", " << locInnermostRingFirstStrawHit->hit->wire->straw << ", " << locInnermostRingLastStrawHit->hit->wire->straw << ", " << locInnermostRingFirstStrawPhi << ", " << locInnermostRingLastStrawPhi << endl;
3735  if(DEBUG_LEVEL > 100)
3736  cout << "final outer ring: ring, first/last straws & phis = " << locOutermostRingFirstStrawHit->hit->wire->ring << ", " << locOutermostRingFirstStrawHit->hit->wire->straw << ", " << locOutermostRingLastStrawHit->hit->wire->straw << ", " << locOutermostRingFirstStrawPhi << ", " << locOutermostRingLastStrawPhi << endl;
3737 
3738  if((locOutermostRingFirstStrawPhi >= locInnermostRingFirstStrawPhi) && (locOutermostRingFirstStrawPhi <= locInnermostRingLastStrawPhi))
3739  return 0.0;
3740  if((locOutermostRingLastStrawPhi >= locInnermostRingFirstStrawPhi) && (locOutermostRingLastStrawPhi <= locInnermostRingLastStrawPhi))
3741  return 0.0;
3742  if((locInnermostRingFirstStrawPhi >= locOutermostRingFirstStrawPhi) && (locInnermostRingFirstStrawPhi <= locOutermostRingLastStrawPhi))
3743  return 0.0; //4th case not needed. this case only needed if innermost ring is one wire across
3744 
3745  //make all 4 comparisons between hits
3746  double locDeltaPhi, locMinDeltaPhi;
3747  locMinDeltaPhi = fabs(locInnermostRingFirstStrawPhi - locOutermostRingFirstStrawPhi);
3748  if(locMinDeltaPhi > M_PI)
3749  locMinDeltaPhi = fabs(locMinDeltaPhi - M_TWO_PI);
3750  if(locOutermostRingFirstStrawHit != locOutermostRingLastStrawHit)
3751  {
3752  locDeltaPhi = fabs(locInnermostRingFirstStrawPhi - locOutermostRingLastStrawPhi);
3753  if(locDeltaPhi > M_PI)
3754  locDeltaPhi = fabs(locDeltaPhi - M_TWO_PI);
3755  if(locDeltaPhi < locMinDeltaPhi)
3756  locMinDeltaPhi = locDeltaPhi;
3757  }
3758  if(locInnermostRingFirstStrawHit == locInnermostRingLastStrawHit)
3759  return locMinDeltaPhi;
3760 
3761  locDeltaPhi = fabs(locInnermostRingLastStrawPhi - locOutermostRingFirstStrawPhi);
3762  if(locDeltaPhi > M_PI)
3763  locDeltaPhi = fabs(locDeltaPhi - M_TWO_PI);
3764  if(locDeltaPhi < locMinDeltaPhi)
3765  locMinDeltaPhi = locDeltaPhi;
3766  if(locOutermostRingFirstStrawHit != locOutermostRingLastStrawHit)
3767  {
3768  locDeltaPhi = fabs(locInnermostRingLastStrawPhi - locOutermostRingLastStrawPhi);
3769  if(locDeltaPhi > M_PI)
3770  locDeltaPhi = fabs(locDeltaPhi - M_TWO_PI);
3771  if(locDeltaPhi < locMinDeltaPhi)
3772  locMinDeltaPhi = locDeltaPhi;
3773  }
3774 
3775  return locMinDeltaPhi;
3776 }
3777 
3778 //------------
3779 // Find_ThetaZ
3780 //------------
3781 bool DTrackCandidate_factory_CDC::Find_ThetaZ(const DHelicalFit* locFit, const vector<DCDCTrkHit*>& locStereoHits, double& locTheta, double& locZ, double& locChiSqPerNDF)
3782 {
3783  // Calculate theta/z for the input stereo hits
3784  if(locStereoHits.empty())
3785  return false;
3786 
3787  if(Find_ThetaZ_Regression(locFit, locStereoHits, locTheta, locZ, locChiSqPerNDF))
3788  return true;
3789  double locThetaMin, locThetaMax;
3790 
3791  // Regression fit failed, try using histogram methods
3792  bool locThetaOKFlag = Find_Theta(locFit, locStereoHits, locTheta, locThetaMin, locThetaMax, locChiSqPerNDF);
3793  if(locThetaOKFlag)
3794  {
3795  if(Find_Z(locFit, locStereoHits, locThetaMin, locThetaMax, locZ))
3796  return true;
3797  }
3798 
3799  // Histogram methods failed.
3800 
3801  // Assume that the track came from the center of the target
3802  locChiSqPerNDF = 9.9E8;
3803  locZ = TARGET_Z;
3804  if(locThetaOKFlag)
3805  return true;
3806 
3807  // Use a point in one of the stereo layers to estimate tanl
3808  double x = locStereoHits[0]->dStereoHitPos.X();
3809  double y = locStereoHits[0]->dStereoHitPos.Y();
3810  double tworc = 2.0*locFit->r0;
3811  double ratio = sqrt(x*x + y*y)/tworc;
3812  if(ratio >= 1.0)
3813  return false;
3814 
3815  double tanl = (locStereoHits[0]->dStereoHitPos.Z() - locZ)/(tworc*asin(ratio));
3816  locTheta = M_PI_2 - atan(tanl);
3817  return true;
3818 }
3819 
3820 //-----------------------
3821 // Find_ThetaZ_Regression
3822 //-----------------------
3823 // Linear regression to find tan(lambda) and z_vertex.
3824 // This method assumes that there are errors in both the z positions and
3825 // the arc lengths.
3826 // Algorithm from Numerical Recipes in C (2nd. ed.), pp. 668-669.
3827 bool DTrackCandidate_factory_CDC::Find_ThetaZ_Regression(const DHelicalFit* locFit, const vector<DCDCTrkHit*>& locStereoHits, double& locTheta, double& locZ, double& locChiSqPerNDF)
3828 {
3829  if(DEBUG_LEVEL > 3)
3830  cout<<"Finding theta and z via linear regression method."<<endl;
3831 
3832  if(locStereoHits.empty() || (!(locFit->normal.Mag() > 0.0)))
3833  return false;
3834 
3835  // Vector of intersections between the circle and the stereo wires
3836  vector<intersection_t> intersections;
3837  for(size_t m = 0; m < locStereoHits.size(); ++m)
3838  {
3839  DCDCTrkHit* trkhit = locStereoHits[m];
3840 
3841  //DVector3_with_perp intersection;
3842  intersection_t intersection;
3843  intersection.x = trkhit->dStereoHitPos.X();
3844  intersection.y = trkhit->dStereoHitPos.Y();
3845  intersection.perp2 = intersection.x*intersection.x + intersection.y*intersection.y;
3846  intersection.z = trkhit->dStereoHitPos.Z();
3847  intersection.var_z = trkhit->var_z;
3848  intersections.push_back(intersection);
3849  }
3850 
3851  // Now, sort the entries
3852  stable_sort(intersections.begin(), intersections.end(), CDCSort_Intersections);
3853 
3854  // Compute the arc lengths between the origin in x and y and (xi,yi)
3855  vector<double> arclengths(intersections.size());
3856  vector<double> ratios(intersections.size());
3857  double xc = locFit->x0;
3858  double yc = locFit->y0;
3859  double rc = locFit->r0;
3860  double two_rc = 2.*rc;
3861 
3862  // Find POCA to beam line
3863  double myphi = atan2(yc, xc);
3864  double y0 = yc - rc*sin(myphi);
3865  double x0 = xc - rc*cos(myphi);
3866 
3867  // Arc length to first measurement
3868  double diffx = intersections[0].x - x0;
3869  double diffy = intersections[0].y - y0;
3870  double chord = sqrt(diffx*diffx + diffy*diffy);
3871  double ratio = chord/two_rc;
3872  double s = (ratio < 1.) ? two_rc*asin(ratio) : M_PI_2*two_rc;
3873  arclengths[0] = s;
3874  ratios[0] = ratio;
3875 
3876  // Find arc lengths for the rest of the stereo hits
3877  for(size_t m = 1; m < arclengths.size(); ++m)
3878  {
3879  diffx = intersections[m].x - intersections[m - 1].x;
3880  diffy = intersections[m].y - intersections[m - 1].y;
3881  chord = sqrt(diffx*diffx + diffy*diffy);
3882  ratio = chord/two_rc;
3883  if(ratio > 0.999)
3884  return false;
3885  double ds = two_rc*asin(ratio);
3886  s += ds;
3887  arclengths[m] = s;
3888  ratios[m] = ratio;
3889  }
3890 
3891  //Linear regression to find z0, tanl
3892  double tanl = 0.,z0 = 0.;
3893  if(arclengths.size() > 1) // Do fit only if have more than one measurement
3894  {
3895  DCDCLineFit fit;
3896  size_t n = fit.n = intersections.size();
3897  fit.s.resize(n);
3898  fit.var_s.resize(n);
3899  fit.z.resize(n);
3900  fit.var_z.resize(n);
3901  fit.w.resize(n);
3902 
3903  // Find average variances for z and s
3904  double avg_var_s = 0., avg_var_z = 0.;
3905  double var_r = 1.6*1.6/12.; // assume cell size
3906  for (size_t m = 0; m < n; ++m)
3907  {
3908  fit.s[m] = arclengths[m];
3909  fit.var_s[m] = var_r/(1. - ratios[m]*ratios[m]);
3910 
3911  avg_var_s += fit.var_s[m];
3912  avg_var_z += intersections[m].var_z;
3913 
3914  if(DEBUG_LEVEL>5)
3915  cout<<"Using CDC hit "<<m<<" z="<<intersections[m].z << " s=" << arclengths[m] <<endl;
3916  }
3917 
3918  // Scale z errors according to the ratio of the average variances
3919  double scale2 = avg_var_s/avg_var_z;
3920  double scale = sqrt(scale2);
3921  vector<double> weight(n);
3922  for (size_t m = 0; m < n; ++m)
3923  {
3924  fit.z[m] = scale*intersections[m].z;
3925  fit.var_z[m] = scale2*intersections[m].var_z;
3926  weight[m] = fit.var_s[m] + fit.var_z[m];
3927  }
3928 
3929  // Perform preliminary fit to find the (scaled) slope tanl
3930  double sumv=0., sumx=0.;
3931  double sumy=0., sumxx=0., sumxy=0.;
3932  for(size_t m = 0; m < n; ++m)
3933  {
3934  //double temp = 1./var_z[m];
3935  double temp = 1./weight[m];
3936  sumv += temp;
3937  sumx += arclengths[m]*temp;
3938  sumy += fit.z[m]*temp;
3939  sumxx += arclengths[m]*arclengths[m]*temp;
3940  sumxy += arclengths[m]*fit.z[m]*temp;
3941  }
3942  double Delta = sumv*sumxx - sumx*sumx;
3943  if(!(fabs(Delta) > 0.0))
3944  return false;
3945 
3946  tanl = (sumv*sumxy - sumx*sumy)/Delta;
3947  fit.z0 = (sumxx*sumy - sumx*sumxy)/Delta;
3948 
3949  // Convert tanl to an angle and create two other reference angles
3950  double angle[3];
3951  angle[0] = 0.;
3952  angle[1] = atan(tanl);
3953  angle[2] = 1.571;
3954  // Compute chi^2 values for line fits with these three angles
3955  double ch[3];
3956  for (unsigned int m = 0; m < 3; ++m)
3957  ch[m] = fit.ChiXY(angle[m]);
3958 
3959  // Bracket the minimum chi^2
3960  fit.BracketMinimumChisq(angle[0], angle[1], angle[2], ch[0], ch[1], ch[2]);
3961  // Find the minimum chi^2 using Brent's method and compute the best value for lambda
3962  double lambda = 0.;
3963  locChiSqPerNDF = fit.FindMinimumChisq(angle[0], angle[1], angle[2], lambda)/2.0; //2 degrees of freedom
3964  // Undo the scaling
3965  z0 = fit.z0/scale;
3966  tanl = tan(lambda)/scale;
3967  }
3968  else
3969  {
3970  z0 = TARGET_Z;
3971  tanl = (intersections[0].z - z0)/arclengths[0];
3972  locChiSqPerNDF = 9.9E9; //only two hits: technically is zero, but if possible want to pick a group of stereo hits with more hits
3973  }
3974 
3975  locTheta = M_PI_2 - atan(tanl);
3976  locZ = z0;
3977 
3978  return true;
3979 }
3980 
3981 //-----------
3982 // Find_Theta
3983 //-----------
3984 bool DTrackCandidate_factory_CDC::Find_Theta(const DHelicalFit* locFit, const vector<DCDCTrkHit*>& locStereoHits, double& locTheta, double& locThetaMin, double& locThetaMax, double& locChiSqPerNDF)
3985 {
3986  if(locStereoHits.empty())
3987  return false;
3988  /// Find the theta value using the input stereo hits.
3989  /// The values for dPhiStereo and dStereoHitPos.Z() are assumed to be valid.
3990  /// The value of locFit.r0 is also used to calculate theta.
3991  ///
3992  /// This uses a histogramming technique that looks at the overlaps of the
3993  /// angle ranges subtended by each hit between the given target limits.
3994  /// The overlaps usually lead to a range of values for theta. The limits
3995  /// of these are stored in locThetaMin and locThetaMax.
3996  /// The centroid of the range is stored in the theta field.
3997 
3998  // We use a simple array to store our histogram here. We don't want to use
3999  // ROOT histograms because they are not thread safe.
4000  unsigned int Nbins = 1000;
4001  unsigned int hist[Nbins];
4002  for(unsigned int i=0; i<Nbins; ++i)
4003  hist[i] = 0; // clear histogram
4004  double bin_width = M_TWO_PI/(double)Nbins;
4005  double hist_low_limit = -M_PI; // lower edge of histogram limits
4006 
4007  // Loop over CDC hits, filling the histogram
4008  double r0 = locFit->r0;
4009  for(unsigned int i=0; i < locStereoHits.size(); ++i)
4010  {
4011  DCDCTrkHit *trkhit = locStereoHits[i];
4012 
4013  // Calculate upper and lower limits in theta
4014  double alpha = r0*trkhit->dPhiStereo;
4015  if(locFit->h < 0.0)
4016  alpha = -alpha;
4017  double tmin = atan2(alpha, trkhit->dStereoHitPos.Z() - VERTEX_Z_MIN);
4018  double tmax = atan2(alpha, trkhit->dStereoHitPos.Z() - VERTEX_Z_MAX);
4019  if(tmin>tmax)
4020  {
4021  double tmp = tmin;
4022  tmin=tmax;
4023  tmax=tmp;
4024  }
4025  if(DEBUG_LEVEL>3)
4026  cout<<" -- phi_stereo="<<trkhit->dPhiStereo<<" z_stereo="<<trkhit->dStereoHitPos.Z()<<" alpha="<<alpha<<endl;
4027  if(DEBUG_LEVEL>3)
4028  cout<<" -- tmin="<<tmin<<" tmax="<<tmax<<endl;
4029 
4030  // Find index of bins corresponding to tmin and tmax
4031  unsigned int imin = (unsigned int)floor((tmin-hist_low_limit)/bin_width);
4032  unsigned int imax = (unsigned int)floor((tmax-hist_low_limit)/bin_width);
4033 
4034  // If entire range of this hit is outside of the histogram limit
4035  // then discard this hit.
4036  if(imin>=Nbins)
4037  continue;
4038 
4039  // Clip limits of bin range to our histogram limits
4040  if(imin>=Nbins)
4041  imin=Nbins-1;
4042  if(imax>=Nbins)
4043  imax=Nbins-1;
4044 
4045  // Increment all bins between imin and imax
4046  for(unsigned int j=imin; j<=imax; ++j)
4047  ++hist[j];
4048  }
4049 
4050  // Look for the indexes of the plateau
4051  unsigned int istart=0;
4052  unsigned int iend=0;
4053  for(unsigned int i=1; i<Nbins; ++i)
4054  {
4055  if(hist[i]>hist[istart])
4056  {
4057  istart = i;
4058  if(DEBUG_LEVEL>3)
4059  cout<<" -- istart="<<istart<<" (theta="<<hist_low_limit + bin_width*(0.5+(double)istart)<<" , N="<<hist[i]<<")"<<endl;
4060  }
4061  if(hist[i] == hist[istart])
4062  iend = i;
4063  }
4064 
4065  // If there are no entries in the histogram, then return false
4066  if(hist[istart] == 0)
4067  return false;
4068 
4069  // Calculate theta limits
4070  locThetaMin = hist_low_limit + bin_width*(0.5+(double)istart);
4071  locThetaMax = hist_low_limit + bin_width*(0.5+(double)iend);
4072  locTheta = (locThetaMax + locThetaMin)/2.0;
4073  if(DEBUG_LEVEL>3)
4074  cout<<"istart="<<istart<<" iend="<<iend<<" theta_min="<<locThetaMin<<" theta_max="<<locThetaMax<<endl;
4075  locChiSqPerNDF = 9.9E5; //NEED TO CALCULATE THIS!!!
4076 
4077  return true;
4078 }
4079 
4080 //-------
4081 // Find_Z
4082 //-------
4083 bool DTrackCandidate_factory_CDC::Find_Z(const DHelicalFit* locFit, const vector<DCDCTrkHit*>& locStereoHits, double locThetaMin, double locThetaMax, double& locZ)
4084 {
4085  if(locStereoHits.empty())
4086  return false;
4087 
4088  /// Find the z value of the vertex using the stereo hits.
4089  /// The values for dPhiStereo and dStereoHitPos.Z() are assumed to be valid.
4090  ///
4091  /// This uses a histogramming technique that looks at the overlaps of the
4092  /// z ranges subtended by each hit between the given theta limits.
4093  /// The overlaps usually lead to a range of values for z_vertex.
4094  /// The centroid of the range is returned as locZ.
4095 
4096  // We use a simple array to store our histogram here. We don't want to use
4097  // ROOT histograms because they are not thread safe.
4098  unsigned int Nbins = 300;
4099  unsigned int hist[Nbins];
4100  for(unsigned int i=0; i<Nbins; ++i)
4101  hist[i] = 0; // clear histogram
4102  double bin_width = 0.5; // bins are 5mm
4103  double hist_low_limit = 0.0; // lower edge of histogram limits
4104 
4105  // Loop over CDC hits, filling the histogram
4106  double r0 = locFit->r0;
4107  double tan_alpha_min = tan(locThetaMin)/r0;
4108  double tan_alpha_max = tan(locThetaMax)/r0;
4109  for(unsigned int i=0; i< locStereoHits.size(); ++i)
4110  {
4111  DCDCTrkHit* trkhit = locStereoHits[i];
4112 
4113  // Calculate upper and lower limits in z
4114  double q_sign = locFit->h > 0.0 ? +1.0:-1.0;
4115  double zmin = trkhit->dStereoHitPos.Z() - q_sign*trkhit->dPhiStereo/tan_alpha_min;
4116  double zmax = trkhit->dStereoHitPos.Z() - q_sign*trkhit->dPhiStereo/tan_alpha_max;
4117  if(zmin>zmax)
4118  {
4119  double tmp = zmin;
4120  zmin=zmax;
4121  zmax=tmp;
4122  }
4123  if(DEBUG_LEVEL>3)
4124  cout<<" -- phi_stereo="<<trkhit->dPhiStereo<<" z_stereo="<<trkhit->dStereoHitPos.Z()<<endl;
4125  if(DEBUG_LEVEL>3)
4126  cout<<" -- zmin="<<zmin<<" zmax="<<zmax<<endl;
4127 
4128  // Find index of bins corresponding to tmin and tmax
4129  unsigned int imin = (unsigned int)floor((zmin-hist_low_limit)/bin_width);
4130  unsigned int imax = (unsigned int)floor((zmax-hist_low_limit)/bin_width);
4131 
4132  // If entire range of this hit is outside of the histogram limit
4133  // then discard this hit.
4134  if(imax<=0 || imin>=Nbins)
4135  continue;
4136 
4137  // Clip limits of bin range to our histogram limits
4138  if(imin>=Nbins)
4139  imin=Nbins-1;
4140  if(imax>=Nbins)
4141  imax=Nbins-1;
4142 
4143  // Increment all bins between imin and imax
4144  for(unsigned int j=imin; j<=imax; ++j)
4145  ++hist[j];
4146  }
4147 
4148  // Look for the indexes of the plateau
4149  unsigned int istart=0;
4150  unsigned int iend=0;
4151  for(unsigned int i=1; i<Nbins; ++i)
4152  {
4153  if(hist[i]>hist[istart])
4154  {
4155  istart = i;
4156  if(DEBUG_LEVEL>3)
4157  cout<<" -- istart="<<istart<<" (z="<<hist_low_limit + bin_width*(0.5+(double)istart)<<" , N="<<hist[i]<<")"<<endl;
4158  }
4159  if(hist[i] == hist[istart])
4160  iend = i;
4161  }
4162 
4163  // If there are no entries in the histogram, then return false
4164  if(hist[istart] == 0)
4165  return false;
4166 
4167  // Calculate z limits
4168  double locZMin = hist_low_limit + bin_width*(0.5+(double)istart);
4169  double locZMax = hist_low_limit + bin_width*(0.5+(double)iend);
4170  locZ = (locZMax + locZMin)/2.0;
4171  if(DEBUG_LEVEL>3)
4172  cout<<"istart="<<istart<<" iend="<<iend<<" z_min="<<locZMin<<" z_max="<<locZMax<<" hits[istart]="<<hist[istart]<<endl;
4173  return true;
4174 }
4175 
4176 //---------------------------
4177 // Recycle_DCDCSuperLayerSeed
4178 //---------------------------
4180 {
4181  // this function should ONLY be called for stereo super layers AFTER the hits have been projected onto the circle (new hit objects were made)
4182  // this is useful for recycling the memory used by the projected hits and seeds
4183  // first loop over the hits: see if can recycle those as well (each hit can be used in multiple seeds)
4184 
4185  vector<DCDCTrkHit*> locHits;
4186  locCDCSuperLayerSeed->Get_Hits(locHits);
4187  for(size_t loc_i = 0; loc_i < locHits.size(); ++loc_i)
4188  {
4189  DCDCTrkHit* locCDCTrkHit = locHits[loc_i];
4190  if(dStereoHitNumUsedMap[locCDCTrkHit] == 1) //this is the last remaining DCDCSuperLayerSeed this hit is used in: recycle it
4191  dCDCTrkHitPool_Available.push_back(locCDCTrkHit);
4192  else
4193  --dStereoHitNumUsedMap[locCDCTrkHit];
4194  }
4195  dCDCSuperLayerSeedPool_Available.push_back(locCDCSuperLayerSeed); //recycle
4196 }
4197 
4198 //---------------------------
4199 // Recycle_DCDCTrackCircle
4200 //---------------------------
4202 {
4203  if(locCDCTrackCircle->fit != NULL)
4204  {
4205  dHelicalFitPool_Available.push_back(locCDCTrackCircle->fit);
4206  locCDCTrackCircle->fit = NULL;
4207  }
4208  locCDCTrackCircle->Reset();
4209  dCDCTrackCirclePool_Available.push_back(locCDCTrackCircle); //recycle
4210 }
4211 
4212 //----------------------
4213 // Set_HitBitPattern_All
4214 //----------------------
4215 void DTrackCandidate_factory_CDC::Set_HitBitPattern_All(vector<DCDCTrackCircle*>& locCDCTrackCircles)
4216 {
4217  unsigned int locNumBits = 8*sizeof(unsigned int);
4218  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
4219  {
4220  DCDCTrackCircle* locCDCTrackCircle = locCDCTrackCircles[loc_i];
4221  locCDCTrackCircle->HitBitPattern.clear();
4222  locCDCTrackCircle->HitBitPattern.resize(dNumCDCHits/(8*sizeof(unsigned int)) + 1);
4223  vector<DCDCTrkHit*> locHits;
4224  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_Axial.size(); ++loc_j)
4225  {
4226  locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_j]->Get_Hits(locHits);
4227  for(size_t loc_k = 0; loc_k < locHits.size(); ++loc_k)
4228  locCDCTrackCircle->HitBitPattern[locHits[loc_k]->index/locNumBits] |= 1 << locHits[loc_k]->index % locNumBits;
4229  }
4230 
4231  if(!locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.empty())
4232  {
4233  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[0].size(); ++loc_j)
4234  {
4235  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[0][loc_j]->Get_Hits(locHits);
4236  for(size_t loc_k = 0; loc_k < locHits.size(); ++loc_k)
4237  locCDCTrackCircle->HitBitPattern[locHits[loc_k]->index/locNumBits] |= 1 << locHits[loc_k]->index % locNumBits;
4238  }
4239  }
4240  if(!locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.empty())
4241  {
4242  for(size_t loc_j = 0; loc_j < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[0].size(); ++loc_j)
4243  {
4244  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[0][loc_j]->Get_Hits(locHits);
4245  for(size_t loc_k = 0; loc_k < locHits.size(); ++loc_k)
4246  locCDCTrackCircle->HitBitPattern[locHits[loc_k]->index/locNumBits] |= 1 << locHits[loc_k]->index % locNumBits;
4247  }
4248  }
4249  }
4250 }
4251 
4252 //---------------------------
4253 // Filter_TrackCircles_Stereo
4254 //---------------------------
4255 void DTrackCandidate_factory_CDC::Filter_TrackCircles_Stereo(vector<DCDCTrackCircle*>& locCDCTrackCircles)
4256 {
4257  if(locCDCTrackCircles.empty())
4258  return;
4259 
4260  //sort track circles so that the ones with the best stereo chisq/ndf are first
4261  stable_sort(locCDCTrackCircles.begin(), locCDCTrackCircles.end(), CDCSortByStereoChiSqPerNDFIncreasing);
4262 
4263  if(DEBUG_LEVEL > 5)
4264  {
4265  cout << "filter stereo, circles sorted by stereo chisq/ndf" << endl;
4266  Print_TrackCircles(locCDCTrackCircles);
4267  }
4268 
4269  //FIRST: Delete super layer seeds if they are shared between circles: delete it from the one with the worst dWeightedChiSqPerDF_Stereo
4270  // This is typically a problem when a track exits the CDC before reaching SL5 or SL6, and picks up the SL5 & SL6 hits from a nearby track instead
4271  // However, DO NOT delete the super layer seed if it is the last one on the track
4272  for(size_t loc_i = 0; loc_i < (locCDCTrackCircles.size() - 1); ++loc_i)
4273  {
4274  //assume this track circle has no wrong seeds (since it has the best chisq/ndf of all circles containing any of these seeds)
4275  DCDCTrackCircle* locTrackCircle_ToCompareTo = locCDCTrackCircles[loc_i];
4276  vector<DCDCSuperLayerSeed*> locStereoSuperLayerSeeds;
4277  locTrackCircle_ToCompareTo->Get_AllStereoSuperLayerSeeds(locStereoSuperLayerSeeds);
4278  //if any of the following track circles has any of the stereo super layer seeds in this track circle, then delete those seeds from those circles
4279  //should recycle...
4280  bool locSeedsStrippedFlag_AnyCircle = false;
4281  for(size_t loc_j = loc_i + 1; loc_j < locCDCTrackCircles.size(); ++loc_j)
4282  {
4283  DCDCTrackCircle* locTrackCircle_Validating = locCDCTrackCircles[loc_j];
4284  if(locTrackCircle_Validating->Get_NumStereoSuperLayerSeeds() <= 1)
4285  continue; //don't strip the last stereo hits!! (stripping isn't perfrect, maybe they are correct, or maybe hit selector will pick the correct ones)
4286  bool locSeedsStrippedFlag = false;
4287  for(size_t loc_k = 0; loc_k < locStereoSuperLayerSeeds.size(); ++loc_k)
4288  {
4289  if(locTrackCircle_Validating->Get_NumStereoSuperLayerSeeds() <= 1)
4290  break;
4291  //remember, can't compare pointers directly (made new objects for projection to track circle), must compare dSuperLayer and dSeedIndex
4292  unsigned int locSuperLayer = locStereoSuperLayerSeeds[loc_k]->dSuperLayer;
4293  unsigned int locSeedIndex = locStereoSuperLayerSeeds[loc_k]->dSeedIndex;
4294  DCDCSuperLayerSeed* locSuperLayerSeed = locTrackCircle_Validating->Get_SuperLayerSeed(locSuperLayer);
4295  if(locSuperLayerSeed == NULL)
4296  continue;
4297  if((locSuperLayerSeed->dSuperLayer != locSuperLayer) || (locSuperLayerSeed->dSeedIndex != locSeedIndex))
4298  continue;
4299  //stereo super layer is shared by both track circles, reject it from the one with the worse stereo chisq/ndf (weighted)
4300  if(DEBUG_LEVEL > 10)
4301  cout << "strip SL" << locSuperLayer << " from track circle " << loc_j << endl;
4302  locTrackCircle_Validating->Strip_StereoSuperLayerSeed(locSuperLayer);
4303  locSeedsStrippedFlag = true; //may want to recalc theta/z
4304  locSeedsStrippedFlag_AnyCircle = true;
4305  }
4306  if(locSeedsStrippedFlag) //recalc theta/z to get new chisq/ndf
4307  Select_CDCSuperLayerSeeds(locTrackCircle_Validating, false);
4308  }
4309 
4310  if(locSeedsStrippedFlag_AnyCircle) //re-sort if fits have been re-performed
4311  stable_sort(locCDCTrackCircles.begin() + loc_i + 1, locCDCTrackCircles.end(), CDCSortByStereoChiSqPerNDFIncreasing);
4312  }
4313 
4314  //restore sort by circle-fit chisq/ndf (weighted)
4315  stable_sort(locCDCTrackCircles.begin(), locCDCTrackCircles.end(), CDCSortByChiSqPerNDFDecreasing);
4316 
4317  if(DEBUG_LEVEL > 5)
4318  {
4319  cout << "filter stereo, circles sorted by axial chisq/ndf" << endl;
4320  Print_TrackCircles(locCDCTrackCircles);
4321  }
4322 }
4323 
4324 //---------------
4325 // Add_UnusedHits
4326 //---------------
4327 void DTrackCandidate_factory_CDC::Add_UnusedHits(vector<DCDCTrackCircle*>& locCDCTrackCircles)
4328 {
4329  if(DEBUG_LEVEL > 5)
4330  cout << "Add unused hits" << endl;
4331 
4332  // If the last super layer of a track is not 7, search for lone, unused hits on the next super layer and add them to the track
4333  // Only add them if they can link to the previous super layer, and wouldn't skip too many rings
4334  // Add at most one hit: prefer the hit on the innermost ring
4335  //If more than one hit on the innermost axial ring: choose the one closest to the circle fit
4336  //If more than one hit on the innermost stereo ring: ambiguous, don't add any hits
4337  for(size_t loc_i = 0; loc_i < locCDCTrackCircles.size(); ++loc_i)
4338  {
4339  DCDCSuperLayerSeed* locLastSuperLayerSeed = locCDCTrackCircles[loc_i]->Get_LastSuperLayerSeed();
4340  unsigned int locLastSuperLayer = locLastSuperLayerSeed->dSuperLayer;
4341  if(DEBUG_LEVEL > 5)
4342  cout << "i, last super layer = " << loc_i << ", " << locLastSuperLayer << endl;
4343  if(locLastSuperLayer == 7)
4344  continue;
4345  unsigned int locSearchSuperLayer = locLastSuperLayer + 1;
4346  const DHelicalFit* locFit = locCDCTrackCircles[loc_i]->fit;
4347 
4348  //make sure the next super layer doesn't correspond to a region where all of the seeds were deleted earlier (density too high)
4349  double locSeedFirstPhi, locSeedLastPhi;
4350  Calc_SuperLayerPhiRange(locLastSuperLayerSeed, locSeedFirstPhi, locSeedLastPhi);
4351  bool locHitDensityTooHighFlag = false;
4352  for(size_t loc_k = 0; loc_k < dRejectedPhiRegions[locSearchSuperLayer].size(); ++loc_k)
4353  {
4354  if(!Check_IfPhiRangesOverlap(locSeedFirstPhi, locSeedLastPhi, dRejectedPhiRegions[locSearchSuperLayer][loc_k].first, dRejectedPhiRegions[locSearchSuperLayer][loc_k].second))
4355  continue;
4356  locHitDensityTooHighFlag = true;
4357  break;
4358  }
4359  if(locHitDensityTooHighFlag)
4360  {
4361  if(DEBUG_LEVEL > 5)
4362  cout << "hit density too high, don't add unused hits" << endl;
4363  continue; //hit density in this region is too high, ignore all hits here
4364  }
4365 
4366  //make sure we don't skip too many rings
4367  int locLastHitRing = locLastSuperLayerSeed->dCDCRingSeeds.back().ring;
4368  if((4*locLastSuperLayer - locLastHitRing) > MAX_NUM_RINGSEED_RINGS_SKIPABLE)
4369  {
4370  if(DEBUG_LEVEL > 5)
4371  cout << "too many rings missing at the end of the last super layer: actual, max = " << 4*locLastSuperLayer - locLastHitRing << ", " << MAX_NUM_RINGSEED_RINGS_SKIPABLE << endl;
4372  continue; //too many rings missing at the end of the last super layer
4373  }
4374 
4375  wire_direction_t locWireDirection;
4376  if((locSearchSuperLayer == 1) || (locSearchSuperLayer == 4) || (locSearchSuperLayer == 7))
4377  locWireDirection = WIRE_DIRECTION_AXIAL;
4378  else if((locSearchSuperLayer == 2) || (locSearchSuperLayer == 6))
4379  locWireDirection = WIRE_DIRECTION_STEREOLEFT;
4380  else
4381  locWireDirection = WIRE_DIRECTION_STEREORIGHT;
4382 
4383  //ok, look for unused hits within a certain angle/distance from the circle fit
4384  DCDCTrkHit* locBestTrkHit = NULL;
4385  int locAmbiguousHitRing = -1; //if != -1, ignore all hits in or above this ring //set if > 1 stereo hit that matches on this ring
4386  double locBestDeltaPhi = 9.9E9; //for axial if > 1 hit on innermost ring
4387  for(size_t loc_j = 0; loc_j < cdchits_by_superlayer[locSearchSuperLayer - 1].size(); ++loc_j)
4388  {
4389  DCDCTrkHit* locTrkHit = cdchits_by_superlayer[locSearchSuperLayer - 1][loc_j];
4390  if(locTrkHit->flags & USED)
4391  continue; //not a lone hit: used in a super layer seed
4392  if(locTrkHit->hit->wire->ring == locAmbiguousHitRing)
4393  continue; // already > 1 stereo hit on this ring: ambiguous as to which hit is best
4394 
4395  //make sure we don't skip too many rings
4396  int locNumRingsSkipped = locTrkHit->hit->wire->ring - locLastHitRing - 1;
4397  if(locNumRingsSkipped > int(MAX_NUM_RINGSEED_RINGS_SKIPABLE))
4398  {
4399  if(DEBUG_LEVEL > 5)
4400  cout << "would skip too many rings: actual, max = " << locNumRingsSkipped << ", " << MAX_NUM_RINGSEED_RINGS_SKIPABLE << endl;
4401  continue; //would skip too many rings
4402  }
4403 
4404  // see if the hit has small-enough transverse distance to the previous super layer
4405  DCDCRingSeed locRingSeed;
4406  locRingSeed.hits.push_back(locTrkHit);
4407  locRingSeed.ring = locTrkHit->hit->wire->ring;
4408  locRingSeed.linked = false;
4409  if(!Attempt_SeedLink(locLastSuperLayerSeed->dCDCRingSeeds.back(), locRingSeed, locLastSuperLayerSeed->dWireOrientation, locWireDirection))
4410  {
4411  if(DEBUG_LEVEL > 5)
4412  cout << "new hit isn't close to wires in previous seed" << endl;
4413  continue; //new hit isn't close to wires in previous seed
4414  }
4415  if(DEBUG_LEVEL > 5)
4416  cout << "hit is close to wires in previous seed, ring = " << locTrkHit->hit->wire->ring << endl;
4417 
4418  // If axial, require that the hit be near the circle fit.
4419  double locDeltaPhi = 9.9E9;
4420  if((locSearchSuperLayer == 4) || (locSearchSuperLayer == 7))
4421  {
4422  // Find the position on the circle that is closest to locTrkHit
4423  const DVector3 locOrigin = locTrkHit->hit->wire->origin;
4424  double dx = locOrigin.x() - locFit->x0;
4425  double dy = locOrigin.y() - locFit->y0;
4426  double one_over_denom = 1.0/sqrt(dx*dx + dy*dy);
4427  double x = locFit->x0 + locFit->r0*dx*one_over_denom;
4428  double y = locFit->y0 + locFit->r0*dy*one_over_denom;
4429  DVector2 locCirclePosition(x, y);
4430 
4431  // Compare phi values to see if the seeds are close enough to link
4432  locDeltaPhi = fabs(locCirclePosition.Phi() - locOrigin.Phi());
4433  while(locDeltaPhi > M_PI)
4434  locDeltaPhi -= M_TWO_PI;
4435  locDeltaPhi *= 180.0/M_PI;
4436  if(DEBUG_LEVEL > 5)
4437  cout << "hit is axial, check if delta phi is close enough: " << fabs(locDeltaPhi) << ", " << MAX_UNUSED_HIT_LINK_ANGLE << endl;
4438  if(fabs(locDeltaPhi) > MAX_UNUSED_HIT_LINK_ANGLE)
4439  continue; //hit is too far away from the current circle fit
4440  }
4441 
4442  //Have a matching unused hit. Now make sure it is the best one so far.
4443 
4444  if(locBestTrkHit == NULL)
4445  {
4446  //No best hit before, save this result
4447  locBestTrkHit = locTrkHit;
4448  locBestDeltaPhi = locDeltaPhi;
4449  if(DEBUG_LEVEL > 5)
4450  cout << "brand new track hit, delta phi = " << locBestDeltaPhi << endl;
4451  continue;
4452  }
4453 
4454  if(locTrkHit->hit->wire->ring > locBestTrkHit->hit->wire->ring)
4455  {
4456  //ring is larger: new hit not as good as the current best one
4457  if(DEBUG_LEVEL > 5)
4458  cout << "new hit not as good as the current best one" << endl;
4459  continue;
4460  }
4461 
4462  if(locTrkHit->hit->wire->ring < locBestTrkHit->hit->wire->ring)
4463  {
4464  //ring is smaller: new hit better than the one we had before
4465  locAmbiguousHitRing = -1;
4466  locBestTrkHit = locTrkHit;
4467  locBestDeltaPhi = locDeltaPhi;
4468  if(DEBUG_LEVEL > 5)
4469  cout << "new best track hit (better ring), delta phi = " << locBestDeltaPhi << endl;
4470  continue;
4471  }
4472 
4473  //The new hit is on the same ring as the previous best hit.
4474 
4475  if((locSearchSuperLayer != 4) && (locSearchSuperLayer != 7))
4476  {
4477  //stereo: can't tell which hit is best, label ring as ambiguous
4478  locAmbiguousHitRing = locBestTrkHit->hit->wire->ring;
4479  locBestTrkHit = NULL;
4480  if(DEBUG_LEVEL > 5)
4481  cout << "stereo, can't tell which hit is best, label ring " << locAmbiguousHitRing << " as ambiguous" << endl;
4482  continue;
4483  }
4484 
4485  //Axial, see if closest to the track circle (smallest delta phi)
4486  if(locDeltaPhi >= locBestDeltaPhi)
4487  {
4488  //delta-phi is larger: new hit not as good as the current best one
4489  if(DEBUG_LEVEL > 5)
4490  cout << "axial, not the best hit, phis = " << locDeltaPhi << ", " << locBestDeltaPhi << endl;
4491  continue;
4492  }
4493 
4494  //delta-phi is smaller: new hit better than the current best one: save it
4495  locBestTrkHit = locTrkHit;
4496  locBestDeltaPhi = locDeltaPhi;
4497  if(DEBUG_LEVEL > 5)
4498  cout << "new best track hit (same ring), delta phi = " << locBestDeltaPhi << endl;
4499  }
4500  if(locBestTrkHit == NULL)
4501  continue; // no hit found for this track (or hits were ambiguous)
4502 
4503  // add best hit to track: create new DCDCSuperLayerSeed for it, add to circle fit
4504  locBestTrkHit->flags |= USED;
4505  DCDCRingSeed locRingSeed;
4506  locRingSeed.hits.push_back(locBestTrkHit);
4507  locRingSeed.ring = locBestTrkHit->hit->wire->ring;
4508  locRingSeed.linked = true;
4509 
4510  DCDCSuperLayerSeed* locNewSuperLayerSeed = Get_Resource_CDCSuperLayerSeed();
4511  locNewSuperLayerSeed->dCDCRingSeeds.push_back(locRingSeed);
4512  locNewSuperLayerSeed->dSuperLayer = locSearchSuperLayer;
4513  locNewSuperLayerSeed->dSeedIndex = dSuperLayerSeeds[locSearchSuperLayer - 1].size();
4514  locNewSuperLayerSeed->linked = true;
4515  locNewSuperLayerSeed->dWireOrientation = locWireDirection;
4516  dSuperLayerSeeds[locSearchSuperLayer - 1].push_back(locNewSuperLayerSeed);
4517  locCDCTrackCircles[loc_i]->Add_LastSuperLayerSeed(locNewSuperLayerSeed);
4518  }
4519 }
4520 
4521 //-----------------------
4522 // Create_TrackCandidiate
4523 //-----------------------
4525 {
4526  DVector3 pos, mom;
4527  if(!Calc_PositionAndMomentum(locCDCTrackCircle, pos, mom))
4528  {
4529  if(DEBUG_LEVEL > 5)
4530  cout << "Track momentum not greater than zero (or NaN), DTrackCandidate object not created." << endl;
4531  return; //don't create object!!
4532  }
4533 
4534  DTrackCandidate *locTrackCandidate = new DTrackCandidate;
4535  //circle fit parameters
4536  locTrackCandidate->rc=locCDCTrackCircle->fit->r0;
4537  locTrackCandidate->xc=locCDCTrackCircle->fit->x0;
4538  locTrackCandidate->yc=locCDCTrackCircle->fit->y0;
4539  Particle_t locPID = (locCDCTrackCircle->fit->h*dFactorForSenseOfRotation > 0.0) ? PiPlus : PiMinus;
4540  locTrackCandidate->setPID(locPID);
4541  locTrackCandidate->chisq = locCDCTrackCircle->fit->chisq;
4542  locTrackCandidate->Ndof = locCDCTrackCircle->fit->ndof;
4543  locTrackCandidate->setPosition(pos);
4544  locTrackCandidate->setMomentum(mom);
4545 
4546  // Add axial hits (if any)
4547  vector<DCDCTrkHit*> locHits;
4548  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_Axial.size(); ++loc_i)
4549  {
4550  locCDCTrackCircle->dSuperLayerSeeds_Axial[loc_i]->Get_Hits(locHits);
4551  for(size_t loc_j = 0; loc_j < locHits.size(); ++loc_j)
4552  {
4553  locTrackCandidate->AddAssociatedObject(locHits[loc_j]->hit);
4554  locTrackCandidate->used_cdc_indexes.push_back(locHits[loc_j]->index);
4555  }
4556  }
4557 
4558  // Add inner stereo hits (if any)
4559  if(!locCDCTrackCircle->dSuperLayerSeeds_InnerStereo.empty())
4560  {
4561  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[0].size(); ++loc_i) //only one seed series: the "best" one
4562  {
4563  locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[0][loc_i]->Get_Hits(locHits);
4564  for(size_t loc_j = 0; loc_j < locHits.size(); ++loc_j)
4565  {
4566  locTrackCandidate->AddAssociatedObject(locHits[loc_j]->hit);
4567  locTrackCandidate->used_cdc_indexes.push_back(locHits[loc_j]->index);
4568  }
4569  }
4570  }
4571 
4572  // Add outer stereo hits (if any)
4573  if(!locCDCTrackCircle->dSuperLayerSeeds_OuterStereo.empty())
4574  {
4575  for(size_t loc_i = 0; loc_i < locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[0].size(); ++loc_i) //only one seed series: the "best" one
4576  {
4577  locCDCTrackCircle->dSuperLayerSeeds_OuterStereo[0][loc_i]->Get_Hits(locHits);
4578  for(size_t loc_j = 0; loc_j < locHits.size(); ++loc_j)
4579  {
4580  locTrackCandidate->AddAssociatedObject(locHits[loc_j]->hit);
4581  locTrackCandidate->used_cdc_indexes.push_back(locHits[loc_j]->index);
4582  }
4583  }
4584  }
4585 
4586  if(DEBUG_LEVEL>3)
4587  cout<<"Final Candidate parameters: p="<<mom.Mag()<<" theta="<<mom.Theta()<<" phi="<<mom.Phi()<<" z="<<pos.Z()<<endl;
4588 
4589  _data.push_back(locTrackCandidate);
4590 }
4591 
4592 //-------------------------
4593 // Calc_PositionAndMomentum
4594 //-------------------------
4596 {
4597  // Get the position and momentum at a fixed radius from the beam line
4598 
4599  // Direction tangent
4600  double tanl = tan(M_PI_2 - locCDCTrackCircle->dTheta);
4601 
4602  // Squared radius of cylinder outside start counter but inside CDC inner
4603  // radius
4604  double r2 = 90.0;
4605 
4606  // Circle parameters
4607  double xc = locCDCTrackCircle->fit->x0;
4608  double yc = locCDCTrackCircle->fit->y0;
4609  double rc = locCDCTrackCircle->fit->r0;
4610  double rc2 = rc*rc;
4611  double xc2 = xc*xc;
4612  double yc2 = yc*yc;
4613  double xc2_plus_yc2 = xc2 + yc2;
4614 
4615  // variables needed for intersection of circles
4616  double a = (r2 - xc2_plus_yc2 - rc2)/(2.*rc);
4617  double temp1 = yc*sqrt(xc2_plus_yc2 - a*a);
4618  double temp2 = xc*a;
4619  double cosphi_plus = (temp2 + temp1)/xc2_plus_yc2;
4620  double cosphi_minus = (temp2 - temp1)/xc2_plus_yc2;
4621 
4622  // Check for intersections
4623  if(!isfinite(temp1) || !isfinite(temp2))
4624  {
4625  // We did not find an intersection between the two circles, so return
4626  // sensible defaults for pos and mom
4627  double my_seed_phi = locCDCTrackCircle->fit->phi;
4628  double my_center_phi = atan2(yc,xc);
4629  double xv = xc - rc*cos(my_center_phi);
4630  double yv = yc - rc*sin(my_center_phi);
4631  pos.SetXYZ(xv, yv, locCDCTrackCircle->dVertexZ);
4632 
4633  double pt = 0.003*fabs(dMagneticField->GetBz(pos.x(), pos.y(), pos.z()))*rc;
4634  mom.SetXYZ(pt*cos(my_seed_phi), pt*sin(my_seed_phi), pt*tanl);
4635  return (mom.Mag() > 0.0);
4636  }
4637 
4638  // if we have intersections, find both solutions
4639  double phi_plus = -acos(cosphi_plus);
4640  double phi_minus = -acos(cosphi_minus);
4641  double x_plus = xc + rc*cosphi_plus;
4642  double x_minus = xc + rc*cosphi_minus;
4643  double y_plus = yc + rc*sin(phi_plus);
4644  double y_minus = yc + rc*sin(phi_minus);
4645 
4646  // if the resulting radial position on the circle from the fit does not agree
4647  // with the radius to which we are matching, we have the wrong sign for phi+
4648  // or phi-
4649  double r2_plus = x_plus*x_plus + y_plus*y_plus;
4650  double r2_minus = x_minus*x_minus + y_minus*y_minus;
4651  if(fabs(r2 - r2_plus) > EPS)
4652  {
4653  phi_plus *= -1.;
4654  y_plus = yc + rc*sin(phi_plus);
4655  }
4656  if(fabs(r2 - r2_minus) > EPS)
4657  {
4658  phi_minus *= -1.;
4659  y_minus = yc + rc*sin(phi_minus);
4660  }
4661 
4662  // Choose phi- or phi+ depending on proximity to one of the cdc hits
4663  DCDCTrkHit* locFirstHit = NULL;
4664  if(locCDCTrackCircle->dSuperLayerSeeds_Axial.empty())
4665  locFirstHit = locCDCTrackCircle->dSuperLayerSeeds_InnerStereo[0][0]->dCDCRingSeeds[0].hits[0];
4666  else
4667  locFirstHit = locCDCTrackCircle->dSuperLayerSeeds_Axial[0]->dCDCRingSeeds[0].hits[0];
4668 
4669  double xwire = locFirstHit->hit->wire->origin.x();
4670  double ywire = locFirstHit->hit->wire->origin.y();
4671  double dx = x_minus - xwire;
4672  double dy = y_minus - ywire;
4673  double d2_minus = dx*dx + dy*dy;
4674  dx = x_plus - xwire;
4675  dy = y_plus - ywire;
4676  double d2_plus = dx*dx + dy*dy;
4677  if(d2_plus > d2_minus)
4678  {
4679  phi_minus *= -1.;
4680  if(locCDCTrackCircle->fit->h < 0)
4681  phi_minus += M_PI;
4682  double myphi = atan2(yc, xc);
4683  double xv = xc - rc*cos(myphi);
4684  double yv = yc - rc*sin(myphi);
4685  double dx = x_minus - xv;
4686  double dy = y_minus - yv;
4687  double chord = sqrt(dx*dx + dy*dy);
4688  double two_rc = 2.*rc;
4689  double ratio = chord/two_rc;
4690  double ds = (ratio < 1.) ? (two_rc*asin(ratio)) : (two_rc*M_PI_2);
4691  pos.SetXYZ(x_minus, y_minus, locCDCTrackCircle->dVertexZ + ds*tanl);
4692 
4693  double pt = 0.003*fabs(dMagneticField->GetBz(pos.x(), pos.y(), pos.z()))*rc;
4694  mom.SetXYZ(pt*sin(phi_minus), pt*cos(phi_minus), pt*tanl);
4695  }
4696  else
4697  {
4698  phi_plus *= -1.;
4699  if(locCDCTrackCircle->fit->h < 0)
4700  phi_plus += M_PI;
4701  double myphi = atan2(yc, xc);
4702  double xv = xc - rc*cos(myphi);
4703  double yv = yc - rc*sin(myphi);
4704  double dx = x_plus - xv;
4705  double dy = y_plus - yv;
4706  double chord = sqrt(dx*dx + dy*dy);
4707  double two_rc = 2.*rc;
4708  double ratio = chord/two_rc;
4709  double ds = (ratio < 1.) ? (two_rc*asin(ratio)) : (two_rc*M_PI_2);
4710  pos.SetXYZ(x_plus, y_plus, locCDCTrackCircle->dVertexZ + ds*tanl);
4711 
4712  double pt =0.003*fabs(dMagneticField->GetBz(pos.x(), pos.y(), pos.z()))*rc;
4713  mom.SetXYZ(pt*sin(phi_plus), pt*cos(phi_plus), pt*tanl);
4714  }
4715  return (mom.Mag() > 0.0);
4716 }
4717 
4718 //------------------
4719 // erun
4720 //------------------
4722 {
4723  return NOERROR;
4724 }
4725 
4726 //------------------
4727 // fini
4728 //------------------
4730 {
4731  // Delete memory in resource pools
4732  for(size_t loc_i = 0; loc_i < dCDCTrkHitPool_All.size(); ++loc_i)
4733  delete dCDCTrkHitPool_All[loc_i];
4734 
4735  for(size_t loc_i = 0; loc_i < dCDCSuperLayerSeedPool_All.size(); ++loc_i)
4736  delete dCDCSuperLayerSeedPool_All[loc_i];
4737 
4738  for(size_t loc_i = 0; loc_i < dHelicalFitPool_All.size(); ++loc_i)
4739  delete dHelicalFitPool_All[loc_i];
4740 
4741  for(size_t loc_i = 0; loc_i < dCDCTrackCirclePool_All.size(); ++loc_i)
4742  delete dCDCTrackCirclePool_All[loc_i];
4743 
4744  return NOERROR;
4745 }
4746 
4748 {
4749  hit = NULL;
4750  index = 0;
4751  flags = NONE;
4752  var_z = 0.0;
4753  dStereoHitPos.SetXYZ(0.0, 0.0, 0.0);
4754  dPhiStereo = 0.0;
4755  dValidStereoHitPosFlag = false;
4756 }
4757 
4759 {
4760  dSuperLayer = 0;
4761  dSeedIndex = 0;
4762  linked = false;
4763  dSpiralLinkParams.clear();
4764  dCDCRingSeeds.clear();
4765 }
4766 
4768 {
4769  vector<DCDCTrkHit*> locRingHits;
4770  for(size_t loc_i = 0; loc_i < dCDCRingSeeds.size(); ++loc_i)
4771  {
4772  if(dCDCRingSeeds[loc_i].ring != locRing)
4773  continue;
4774  locRingHits = dCDCRingSeeds[loc_i].hits;
4775  break;
4776  }
4777 
4778  vector<DCDCTrkHit*> locRingHits_CompareTo;
4779  for(size_t loc_i = 0; loc_i < locCDCSuperLayerSeed->dCDCRingSeeds.size(); ++loc_i)
4780  {
4781  if(locCDCSuperLayerSeed->dCDCRingSeeds[loc_i].ring != locRing)
4782  continue;
4783  locRingHits_CompareTo = locCDCSuperLayerSeed->dCDCRingSeeds[loc_i].hits;
4784  break;
4785  }
4786 
4787  return (locRingHits == locRingHits_CompareTo);
4788 }
4789 
4791 {
4792  dSuperLayerSeeds_Axial.clear();
4793  dSuperLayerSeeds_InnerStereo.clear();
4794  dSuperLayerSeeds_OuterStereo.clear();
4795  fit = NULL;
4796  dWeightedChiSqPerDF = 0.0;
4797  dWeightedChiSqPerDF_Stereo = 0.0;
4798  dAverageDriftTime = 0.0;
4799  HitBitPattern.clear();
4800  dTheta = 0.0;
4801  dVertexZ = 0.0;
4802  dSpiralTurnRing = -1;
4803  dTruncationSourceCircles.clear();
4804  dHasNonTruncatedSeedsFlag_InnerStereo = false;
4805  dHasNonTruncatedSeedsFlag_OuterStereo = false;
4806 }
4807 
4809 {
4810  //only checks the first combination of stereo seeds
4811  DCDCSuperLayerSeed* locLastAxialSuperLayerSeed = NULL;
4812  if(!dSuperLayerSeeds_Axial.empty())
4813  {
4814  locLastAxialSuperLayerSeed = dSuperLayerSeeds_Axial.back();
4815  if(locLastAxialSuperLayerSeed->dSuperLayer == 7)
4816  return locLastAxialSuperLayerSeed;
4817  }
4818  if(!dSuperLayerSeeds_OuterStereo.empty())
4819  {
4820  DCDCSuperLayerSeed* locLastOuterStereoSuperLayerSeed = dSuperLayerSeeds_OuterStereo[0].back();
4821  if(locLastOuterStereoSuperLayerSeed != NULL){
4822  if(locLastAxialSuperLayerSeed == NULL) return locLastOuterStereoSuperLayerSeed;
4823  if(locLastOuterStereoSuperLayerSeed->dSuperLayer > locLastAxialSuperLayerSeed->dSuperLayer){
4824  return locLastOuterStereoSuperLayerSeed;
4825  }else{
4826  return locLastAxialSuperLayerSeed;
4827  }
4828  }
4829  }
4830  if(!dSuperLayerSeeds_InnerStereo.empty())
4831  {
4832  DCDCSuperLayerSeed* locLastInnerStereoSuperLayerSeed = dSuperLayerSeeds_InnerStereo[0].back();
4833  if(locLastInnerStereoSuperLayerSeed != NULL){
4834  if(locLastAxialSuperLayerSeed == NULL) return locLastInnerStereoSuperLayerSeed;
4835  if(locLastInnerStereoSuperLayerSeed->dSuperLayer > locLastAxialSuperLayerSeed->dSuperLayer){
4836  return locLastInnerStereoSuperLayerSeed;
4837  }else{
4838  return locLastAxialSuperLayerSeed;
4839  }
4840  }
4841  }
4842  return locLastAxialSuperLayerSeed;
4843 }
4844 
4846 {
4847  //only checks the first combination of stereo seeds
4848  if((locSuperLayer == 1) || (locSuperLayer == 4) || (locSuperLayer == 7))
4849  {
4850  for(size_t loc_i = 0; loc_i < dSuperLayerSeeds_Axial.size(); ++loc_i)
4851  {
4852  if(dSuperLayerSeeds_Axial[loc_i]->dSuperLayer == locSuperLayer)
4853  return dSuperLayerSeeds_Axial[loc_i];
4854  }
4855  return NULL;
4856  }
4857  else if((locSuperLayer == 2) || (locSuperLayer == 3))
4858  {
4859  if(dSuperLayerSeeds_InnerStereo.empty())
4860  return NULL;
4861  for(size_t loc_i = 0; loc_i < dSuperLayerSeeds_InnerStereo[0].size(); ++loc_i)
4862  {
4863  if(dSuperLayerSeeds_InnerStereo[0][loc_i]->dSuperLayer == locSuperLayer)
4864  return dSuperLayerSeeds_InnerStereo[0][loc_i];
4865  }
4866  }
4867  else //outer SL seeds could be listed as inner (e.g. no SL4)
4868  {
4869  if(!dSuperLayerSeeds_OuterStereo.empty())
4870  {
4871  for(size_t loc_i = 0; loc_i < dSuperLayerSeeds_OuterStereo[0].size(); ++loc_i)
4872  {
4873  if(dSuperLayerSeeds_OuterStereo[0][loc_i]->dSuperLayer == locSuperLayer)
4874  return dSuperLayerSeeds_OuterStereo[0][loc_i];
4875  }
4876  }
4877  if(!dSuperLayerSeeds_InnerStereo.empty())
4878  {
4879  for(size_t loc_i = 0; loc_i < dSuperLayerSeeds_InnerStereo[0].size(); ++loc_i)
4880  {
4881  if(dSuperLayerSeeds_InnerStereo[0][loc_i]->dSuperLayer == locSuperLayer)
4882  return dSuperLayerSeeds_InnerStereo[0][loc_i];
4883  }
4884  }
4885  }
4886  return NULL;
4887 }
4888 
4890 {
4891  //assumes at most one stereo series of each type!!!
4892  vector<DCDCSuperLayerSeed*>::iterator locIterator;
4893  if(!dSuperLayerSeeds_OuterStereo.empty())
4894  {
4895  for(locIterator = dSuperLayerSeeds_OuterStereo[0].begin(); locIterator != dSuperLayerSeeds_OuterStereo[0].end(); ++locIterator)
4896  {
4897  if((*locIterator)->dSuperLayer != locSuperLayer)
4898  continue;
4899  dSuperLayerSeeds_OuterStereo[0].erase(locIterator);
4900  if(dSuperLayerSeeds_OuterStereo[0].empty())
4901  dSuperLayerSeeds_OuterStereo.clear();
4902  return;
4903  }
4904  }
4905  if(!dSuperLayerSeeds_InnerStereo.empty())
4906  {
4907  for(locIterator = dSuperLayerSeeds_InnerStereo[0].begin(); locIterator != dSuperLayerSeeds_InnerStereo[0].end(); ++locIterator)
4908  {
4909  if((*locIterator)->dSuperLayer != locSuperLayer)
4910  continue;
4911  dSuperLayerSeeds_InnerStereo[0].erase(locIterator);
4912  if(dSuperLayerSeeds_InnerStereo[0].empty())
4913  dSuperLayerSeeds_InnerStereo.clear();
4914  return;
4915  }
4916  }
4917 }
4918 
4920 {
4921  //assumes at most one stereo series of each type!!!
4922  unsigned int locSuperLayer = locSuperLayerSeed->dSuperLayer;
4923  if((locSuperLayer == 1) || (locSuperLayer == 4) || (locSuperLayer == 7))
4924  dSuperLayerSeeds_Axial.push_back(locSuperLayerSeed);
4925  else if((locSuperLayer == 2) || (locSuperLayer == 3))
4926  {
4927  if(dSuperLayerSeeds_InnerStereo.empty())
4928  dSuperLayerSeeds_InnerStereo.resize(1);
4929  dSuperLayerSeeds_InnerStereo[0].push_back(locSuperLayerSeed);
4930  }
4931  else //is super layer 5 or 6
4932  {
4933  unsigned int locLastAxialLayer = dSuperLayerSeeds_Axial.empty() ? 0 : dSuperLayerSeeds_Axial.back()->dSuperLayer;
4934  if(dSuperLayerSeeds_InnerStereo.empty() || (locLastAxialLayer == 4))
4935  {
4936  if(dSuperLayerSeeds_OuterStereo.empty())
4937  dSuperLayerSeeds_OuterStereo.resize(1);
4938  dSuperLayerSeeds_OuterStereo[0].push_back(locSuperLayerSeed);
4939  }
4940  else //put in inner stereo to keep combinations correct
4941  dSuperLayerSeeds_InnerStereo[0].push_back(locSuperLayerSeed);
4942  }
4943 }
4944 
4946 {
4947  //truncate this circle by rejecting all super layers down to locNewLastSuperLayer
4948  //DOES NOT recycle any memory (these seeds may be used by other circles!!)
4949  for(size_t loc_i = 0; loc_i < dSuperLayerSeeds_Axial.size(); ++loc_i)
4950  {
4951  if(dSuperLayerSeeds_Axial[loc_i]->dSuperLayer <= locNewLastSuperLayer)
4952  continue;
4953  ((loc_i == 0) ? dSuperLayerSeeds_Axial.clear() : dSuperLayerSeeds_Axial.resize(loc_i));
4954  break;
4955  }
4956 
4957  //outer stereo
4958  vector<vector<DCDCSuperLayerSeed*> >::iterator locIterator, locIterator2;
4959  if(locNewLastSuperLayer < 5)
4960  dSuperLayerSeeds_OuterStereo.clear();
4961  else if(locNewLastSuperLayer < 7)
4962  {
4963  bool locClippedEveryStereoSeedFlag = true;
4964  for(locIterator = dSuperLayerSeeds_OuterStereo.begin(); locIterator != dSuperLayerSeeds_OuterStereo.end();)
4965  {
4966  vector<DCDCSuperLayerSeed*>& locSeedSeries = *locIterator;
4967  bool locClippedstereoSeriesFlag = false;
4968  for(size_t loc_j = 0; loc_j < locSeedSeries.size(); ++loc_j)
4969  {
4970  if(locSeedSeries[loc_j]->dSuperLayer <= locNewLastSuperLayer)
4971  continue;
4972  locClippedstereoSeriesFlag = true;
4973  if(loc_j == 0)
4974  {
4975  locSeedSeries.clear();
4976  break;
4977  }
4978  locSeedSeries.resize(loc_j);
4979  //now, check if another seed series is exactly like this one: if so, clear it
4980  for(locIterator2 = dSuperLayerSeeds_OuterStereo.begin(); locIterator2 != dSuperLayerSeeds_OuterStereo.end(); ++locIterator2)
4981  {
4982  if(locIterator2 == locIterator)
4983  continue;
4984  vector<DCDCSuperLayerSeed*>& locSeedSeries2 = *locIterator2;
4985  if(locSeedSeries == locSeedSeries2)
4986  {
4987  locSeedSeries.clear();
4988  break;
4989  }
4990  }
4991  break;
4992  }
4993  if(!locClippedstereoSeriesFlag)
4994  locClippedEveryStereoSeedFlag = false;
4995  (locSeedSeries.empty() ? (locIterator = dSuperLayerSeeds_OuterStereo.erase(locIterator)) : ++locIterator);
4996  }
4997  if(locClippedEveryStereoSeedFlag)
4998  dHasNonTruncatedSeedsFlag_OuterStereo = false;
4999  }
5000 
5001  //inner stereo
5002  if(locNewLastSuperLayer < 2)
5003  {
5004  dSuperLayerSeeds_InnerStereo.clear();
5005  return;
5006  }
5007  else if(locNewLastSuperLayer < 7) //7 instead of 4: could be outer super layers in inner (if SL4 is missing)
5008  {
5009  bool locClippedEveryStereoSeedFlag = true;
5010  for(locIterator = dSuperLayerSeeds_InnerStereo.begin(); locIterator != dSuperLayerSeeds_InnerStereo.end();)
5011  {
5012  vector<DCDCSuperLayerSeed*>& locSeedSeries = *locIterator;
5013  bool locClippedstereoSeriesFlag = false;
5014  for(size_t loc_j = 0; loc_j < locSeedSeries.size(); ++loc_j)
5015  {
5016  if(locSeedSeries[loc_j]->dSuperLayer <= locNewLastSuperLayer)
5017  continue;
5018  locClippedstereoSeriesFlag = true;
5019  if(loc_j == 0)
5020  {
5021  locSeedSeries.clear();
5022  break;
5023  }
5024  locSeedSeries.resize(loc_j);
5025  //now, check if another seed series is exactly like this one: if so, clear it
5026  for(locIterator2 = dSuperLayerSeeds_InnerStereo.begin(); locIterator2 != dSuperLayerSeeds_InnerStereo.end(); ++locIterator2)
5027  {
5028  if(locIterator2 == locIterator)
5029  continue;
5030  vector<DCDCSuperLayerSeed*>& locSeedSeries2 = *locIterator2;
5031  if(locSeedSeries == locSeedSeries2)
5032  {
5033  locSeedSeries.clear();
5034  break;
5035  }
5036  }
5037  break;
5038  }
5039  if(!locClippedstereoSeriesFlag)
5040  locClippedEveryStereoSeedFlag = false;
5041  (locSeedSeries.empty() ? (locIterator = dSuperLayerSeeds_InnerStereo.erase(locIterator)) : ++locIterator);
5042  }
5043  if(locClippedEveryStereoSeedFlag)
5044  dHasNonTruncatedSeedsFlag_InnerStereo = false;
5045  }
5046 }
5047 
5049 {
5050  //used when merging track circles: this track circle will absorb the stereo combinations from the other one
5051  for(size_t loc_i = 0; loc_i < locTrackCircle->dSuperLayerSeeds_InnerStereo.size(); ++loc_i)
5052  {
5053  const vector<DCDCSuperLayerSeed*>& locSeedSeries = locTrackCircle->dSuperLayerSeeds_InnerStereo[loc_i];
5054  bool locComboAlreadyPresentFlag = false;
5055  for(size_t loc_j = 0; loc_j < dSuperLayerSeeds_InnerStereo.size(); ++loc_j)
5056  {
5057  if(locSeedSeries == dSuperLayerSeeds_InnerStereo[loc_j])
5058  {
5059  locComboAlreadyPresentFlag = true;
5060  break;
5061  }
5062  else if((locSeedSeries.size() == 1) && (locSeedSeries[0] == dSuperLayerSeeds_InnerStereo[loc_j][0]))
5063  {
5064  locComboAlreadyPresentFlag = true; //is a subset of an existing combo
5065  break;
5066  }
5067  }
5068  if(!locComboAlreadyPresentFlag)
5069  dSuperLayerSeeds_InnerStereo.push_back(locSeedSeries);
5070  }
5071 
5072  for(size_t loc_i = 0; loc_i < locTrackCircle->dSuperLayerSeeds_OuterStereo.size(); ++loc_i)
5073  {
5074  const vector<DCDCSuperLayerSeed*>& locSeedSeries = locTrackCircle->dSuperLayerSeeds_OuterStereo[loc_i];
5075  bool locComboAlreadyPresentFlag = false;
5076  for(size_t loc_j = 0; loc_j < dSuperLayerSeeds_OuterStereo.size(); ++loc_j)
5077  {
5078  if(locSeedSeries == dSuperLayerSeeds_OuterStereo[loc_j])
5079  {
5080  locComboAlreadyPresentFlag = true;
5081  break;
5082  }
5083  else if((locSeedSeries.size() == 1) && (locSeedSeries[0] == dSuperLayerSeeds_OuterStereo[loc_j][0]))
5084  {
5085  locComboAlreadyPresentFlag = true; //is a subset of an existing combo
5086  break;
5087  }
5088  }
5089  if(!locComboAlreadyPresentFlag)
5090  dSuperLayerSeeds_OuterStereo.push_back(locSeedSeries);
5091  }
5092 
5093  if(locTrackCircle->dHasNonTruncatedSeedsFlag_InnerStereo)
5094  dHasNonTruncatedSeedsFlag_InnerStereo = true;
5095  if(locTrackCircle->dHasNonTruncatedSeedsFlag_OuterStereo)
5096  dHasNonTruncatedSeedsFlag_OuterStereo = true;
5097 
5098  for(size_t loc_i = 0; loc_i < locTrackCircle->dTruncationSourceCircles.size(); ++loc_i)
5099  {
5100  bool locIsAlreadyTruncationSourceFlag = false;
5101  for(size_t loc_j = 0; loc_j < dTruncationSourceCircles.size(); ++loc_j)
5102  {
5103  if(locTrackCircle->dTruncationSourceCircles[loc_i] != dTruncationSourceCircles[loc_j])
5104  continue;
5105  locIsAlreadyTruncationSourceFlag = true;
5106  break;
5107  }
5108  if(!locIsAlreadyTruncationSourceFlag)
5109  dTruncationSourceCircles.push_back(locTrackCircle->dTruncationSourceCircles[loc_i]);
5110  }
5111 }
5112 
5114 {
5115  //returns false if they are effectively identical
5116  if(locTrackCircle->dSuperLayerSeeds_Axial.empty())
5117  return false;
5118  if(locTrackCircle->Get_LastSuperLayerSeed()->dSuperLayer == 7)
5119  return false; //can't be subset if hasn't been truncated yet
5120  if(locTrackCircle->dSuperLayerSeeds_Axial.size() >= dSuperLayerSeeds_Axial.size())
5121  return false; //can't be subset if same # or greater of axial super layers (if identical should merge them instead)
5122 
5123  for(size_t loc_i = 0; loc_i < locTrackCircle->dSuperLayerSeeds_Axial.size(); ++loc_i)
5124  {
5125  DCDCSuperLayerSeed* locSuperLayerSeed = locTrackCircle->dSuperLayerSeeds_Axial[loc_i];
5126  if(Get_SuperLayerSeed(locSuperLayerSeed->dSuperLayer) != locSuperLayerSeed)
5127  return false;
5128  }
5129  //all axial seeds are a subset, now check the stereo dHasNonTruncatedSeedsFlag flags
5130  DCDCSuperLayerSeed* locLastSuperLayerSeed = locTrackCircle->Get_LastSuperLayerSeed();
5131  if((locLastSuperLayerSeed->dSuperLayer == 1) || (locLastSuperLayerSeed->dSuperLayer == 4))
5132  return true;
5133 
5134  DCDCSuperLayerSeed* locLastAxialSuperLayerSeed = locTrackCircle->dSuperLayerSeeds_Axial.back();
5135  if(locLastAxialSuperLayerSeed->dSuperLayer == 4)
5136  return locTrackCircle->dHasNonTruncatedSeedsFlag_OuterStereo;
5137  else
5138  return locTrackCircle->dHasNonTruncatedSeedsFlag_InnerStereo;
5139 }
5140 
5141 void DTrackCandidate_factory_CDC::DCDCTrackCircle::Get_AllStereoSuperLayerSeeds(vector<DCDCSuperLayerSeed*>& locStereoSuperLayerSeeds)
5142 {
5143  //assumes there is only one seed series
5144  locStereoSuperLayerSeeds.clear();
5145  if(!dSuperLayerSeeds_InnerStereo.empty())
5146  locStereoSuperLayerSeeds = dSuperLayerSeeds_InnerStereo[0];
5147  if(!dSuperLayerSeeds_OuterStereo.empty())
5148  locStereoSuperLayerSeeds.insert(locStereoSuperLayerSeeds.begin(), dSuperLayerSeeds_OuterStereo[0].begin(), dSuperLayerSeeds_OuterStereo[0].end());
5149 }
5150 
5152 {
5153  //assumes there is only one seed series
5154  unsigned int locNumStereoSuperLayerSeeds = 0;
5155  if(!dSuperLayerSeeds_InnerStereo.empty())
5156  locNumStereoSuperLayerSeeds += dSuperLayerSeeds_InnerStereo[0].size();
5157  if(!dSuperLayerSeeds_OuterStereo.empty())
5158  locNumStereoSuperLayerSeeds += dSuperLayerSeeds_OuterStereo[0].size();
5159  return locNumStereoSuperLayerSeeds;
5160 }
5161 
5162 //-------------------------------------------------------------------------
5163 // Routines for fitting a line to the stereo data
5164 //-------------------------------------------------------------------------
5165 // Compute the chi^2 for a line fit given errors in both s and z. Also
5166 // computes current best guess for the scaled intercept z0.
5167 // Taken from Numerical Recipes in C (2nd ed.), p. 670.
5169 {
5170  double tanl=tan(lambda);
5171  double sumw=0.,avg_s=0.,avg_z=0.,my_chi2=0.;
5172  for (unsigned i=0;i<n;i++){
5173  w[i]=1./(tanl*tanl*var_s[i]+var_z[i]);
5174  sumw+=w[i];
5175  avg_s+=w[i]*s[i];
5176  avg_z+=w[i]*z[i];
5177  }
5178  avg_s/=sumw;
5179  avg_z/=sumw;
5180  z0=avg_z-tanl*avg_s;
5181  for (unsigned int i=0;i<n;i++){
5182  double temp=z[i]-z0-tanl*s[i];
5183  my_chi2+=w[i]*temp*temp;
5184  }
5185  return my_chi2;
5186 }
5187 
5188 // Routine to bracket the minimum chi^2, from Numerical Recipes in C (2nd ed.),
5189 // pp. 400-401.
5190 #define SHFT(w,x,y,z) (w)=(x);(x)=(y);(y)=(z)
5191 #define SIGN(x,y) ((y)>=0.0 ? fabs(x):-fabs(x))
5192 void DTrackCandidate_factory_CDC::DCDCLineFit::BracketMinimumChisq(double &a,double &b,double &c,double &chi2a,double &chi2b,double &chi2c)
5193 {
5194  const double GOLD=1.618034;
5195  const double GLIMIT=100.0;
5196 
5197  chi2a=ChiXY(a);
5198  chi2b=ChiXY(b);
5199  double chi2u=0.;
5200  if (chi2b>chi2a){
5201  double dummy=0.;
5202  SHFT(dummy,a,b,dummy);
5203  SHFT(dummy,chi2b,chi2a,dummy);
5204  }
5205  c=b+GOLD*(b-a);
5206  chi2c=ChiXY(c);
5207  while (chi2b>chi2c){
5208  double r=(b-a)*(chi2b-chi2c);
5209  double q=(b-c)*(chi2b-chi2a);
5210  double q_minus_r=q-r;
5211  double fabs_q_minus_r=fabs(q_minus_r);
5212  double max=(fabs_q_minus_r>1.e-20)?fabs_q_minus_r:1.e-20;
5213  double u=b-((b-c)*q-(b-a)*r)/(2.*SIGN(max,q_minus_r));
5214  double ulim=b+GLIMIT*(c-b);
5215  if ((b-u)*(u-c)>0.0){
5216  chi2u=ChiXY(u);
5217  if (chi2u<chi2c){
5218  a=b;
5219  b=u;
5220  chi2a=chi2b;
5221  chi2b=chi2u;
5222  return;
5223  }
5224  else if (chi2u>chi2b){
5225  c=u;
5226  chi2c=chi2u;
5227  return;
5228  }
5229  u=c+GOLD*(c-b);
5230  chi2u=ChiXY(u);
5231  }
5232  else if ((c-u)*(u-ulim)>0.0){
5233  chi2u=ChiXY(u);
5234  if (chi2u<chi2c){
5235  SHFT(b,c,u,c+GOLD*(c-b));
5236  SHFT(chi2b,chi2c,chi2u,ChiXY(u));
5237  }
5238  }
5239  else if ((u-ulim)*(ulim-c)>=0.0){
5240  u=ulim;
5241  chi2u=ChiXY(u);
5242  }
5243  else{
5244  u=c+GOLD*(c-b);
5245  chi2u=ChiXY(u);
5246  }
5247  SHFT(a,b,c,u);
5248  SHFT(chi2a,chi2b,chi2c,chi2u);
5249  }
5250 }
5251 
5252 // Use Brent's algorithm to find the "true" (within tolerance) minimum chi^2
5253 // after bracketting. Taken from Numerical Recipes in C (2nd. Ed.), pp. 404-405.
5254 double DTrackCandidate_factory_CDC::DCDCLineFit::FindMinimumChisq(double ax,double bx, double cx, double &xmin)
5255 {
5256  const double CGOLD=0.3819660;
5257  double a=(ax<cx)?ax:cx;
5258  double b=(ax>cx)?ax:cx;
5259  double x=bx,w=bx,v=bx;
5260  double fx=ChiXY(x),fv=fx,fw=fx,fu=0.;
5261  double tol=1e-3,err=0.0,d=0.,u=0.;
5262  for (int iter=1;iter<=100;iter++){
5263  double xm=0.5*(a+b);
5264  double tol1=tol*fabs(x)+1e-10;
5265  double tol2=2.0*tol1;
5266  if (fabs(x-xm)<=(tol2-0.5*(b-a))){
5267  xmin=x;
5268  return fx;
5269  }
5270  if (fabs(err)>tol1){
5271  double r=(x-w)*(fx-fv);
5272  double q=(x-v)*(fx-fw);
5273  double p=(x-v)*q-(x-w)*r;
5274  q=2.0*(q-r);
5275  if (q>0.0) p=-p;
5276  q=fabs(q);
5277  double etemp=err;
5278  err=d;
5279  if (fabs(p)>=fabs(0.5*q*etemp) || p<=q*(a-x)|| p>=q*(b-x)){
5280  d=CGOLD*(err=(x>=xm ? a-x : b-x));
5281  }
5282  else{
5283  d=p/q;
5284  u=x+d;
5285  if (u-a < tol2 || b-u < tol2) d=SIGN(tol1,xm-x);
5286  }
5287  } else {
5288  d=CGOLD*(err=(x>=xm ? a-x : b-x ));
5289  }
5290  u=(fabs(d)>=tol1 ? x+d : x+SIGN(tol1,d));
5291  fu=ChiXY(u);
5292  if (fu<=fx){
5293  if (u>=x) a=x;
5294  else b=x;
5295  SHFT(v,w,x,u);
5296  SHFT(fv,fw,fx,fu);
5297  }
5298  else{
5299  if (u<x) a=u;
5300  else b=u;
5301  if (fu<=fw || w==x){
5302  v=w;
5303  w=u;
5304  fv=fw;
5305  fw=fu;
5306  }
5307  else if (fu<=fv || v==x || v==w){
5308  v=u;
5309  fv=fu;
5310  }
5311  }
5312  }
5313  xmin=x;
5314  return fx;
5315 }
5316 
bool SearchFor_SpiralTurn_TwoSeedsSharingFewHits(DCDCSuperLayerSeed *locSuperLayerSeed1, DCDCSuperLayerSeed *locSuperLayerSeed2)
void setMomentum(const DVector3 &aMomentum)
void Calc_SuperLayerPhiRange(DCDCSuperLayerSeed *locSuperLayerSeed, double &locSeedFirstPhi, double &locSeedLastPhi)
bool Find_Theta(const DHelicalFit *locFit, const vector< DCDCTrkHit * > &locStereoHits, double &locTheta, double &locThetaMin, double &locThetaMax, double &locChiSqPerNDF)
DCDCSuperLayerSeed * Get_SuperLayerSeed(unsigned int locSuperLayer) const
#define SIGN(x, y)
jerror_t Get_CDCHits(JEventLoop *loop)
jerror_t init(void)
Called once at program start.
const DCDCWire * wire
Definition: DCDCTrackHit.h:37
void Filter_TrackCircles_Stereo(vector< DCDCTrackCircle * > &locCDCTrackCircles)
TVector2 DVector2
Definition: DVector2.h:9
bool Check_IfInputIsSubset(const DCDCTrackCircle *locTrackCircle)
TVector3 DVector3
Definition: DVector3.h:14
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
void Truncate_Circle(unsigned int locNewLastSuperLayer)
bool SearchFor_SpiralTurn_MissingOrBetweenRings(DCDCSuperLayerSeed *locSuperLayerSeed1, DCDCSuperLayerSeed *locSuperLayerSeed2)
#define c
#define y
DMagneticFieldMap * GetBfield(unsigned int run_number=1)
jerror_t brun(JEventLoop *locEventLoop, int32_t runnumber)
Called everytime a new run number is detected.
jerror_t fini(void)
Called after last event of last event source has been processed.
bool SearchFor_SpiralTurn_ManyHitsAdjacentRing(DCDCSuperLayerSeed *locSuperLayerSeed1, DCDCSuperLayerSeed *locSuperLayerSeed2, int locRingToCheck, int locMinStrawsAdjacentRing, int &locMaxSpiralNumHits)
bool Check_IfShouldAttemptLink(const DCDCSuperLayerSeed *locSuperLayerSeed, bool locInnerSeedFlag)
bool Link_SuperLayers(vector< DCDCTrackCircle * > &locCDCTrackCircles, unsigned int locOuterSuperLayer)
void Create_TrackCandidiate(DCDCTrackCircle *locCDCTrackCircle)
vector< const DCDCTrackCircle * > dTruncationSourceCircles
bool Find_Z(const DHelicalFit *locFit, const vector< DCDCTrkHit * > &locStereoHits, double locThetaMin, double locThetaMax, double &locZ)
#define CGOLD
DCDCSuperLayerSeed * Create_NewStereoSuperLayerSeed(DCDCSuperLayerSeed *locCDCSuperLayerSeed, const DCDCTrackCircle *locCDCTrackCircle, map< DCDCTrkHit *, DCDCTrkHit * > &locProjectedStereoHitMap)
double zmax
vector< vector< DCDCSuperLayerSeed * > > dSuperLayerSeeds_InnerStereo
vector< vector< DCDCSuperLayerSeed * > > dSuperLayerSeeds_OuterStereo
jerror_t FitCircleRiemann(float rc=0.)
Definition: DHelicalFit.cc:505
void Add_UnusedHits(vector< DCDCTrackCircle * > &locCDCTrackCircles)
static char index(char c)
Definition: base64.cpp:115
void Reject_SuperLayerSeeds_HighSeedDensity(unsigned int locSuperLayer)
DVector3 normal
Definition: DHelicalFit.h:164
void Handle_StereoAndFilter(vector< DCDCTrackCircle * > &locCDCTrackCircles, bool locFinalPassFlag)
bool GetCDCWires(vector< vector< DCDCWire * > > &cdcwires) const
Definition: DGeometry.cc:773
jerror_t AddHitXYZ(float x, float y, float z)
Definition: DHelicalFit.cc:200
jerror_t erun(void)
Called everytime run number changes, provided brun has been called.
void Print_TrackCircle(DCDCTrackCircle *locCDCTrackCircle)
#define M_TWO_PI
void Get_AllStereoSuperLayerSeeds(vector< DCDCSuperLayerSeed * > &locStereoSuperLayerSeeds)
void Link_RingSeeds(vector< DCDCRingSeed * > &parent, ringiter ring, ringiter ringend, unsigned int locSuperLayer, unsigned int locNumPreviousRingsWithoutHit)
void Recycle_DCDCSuperLayerSeed(DCDCSuperLayerSeed *locCDCSuperLayerSeed)
DCDCTrackCircle * Get_Resource_CDCTrackCircle(void)
void Calc_StereoHitDeltaPhis(unsigned int locSuperLayer, vector< DCDCTrkHit * > &locHits, const DCDCTrackCircle *locCDCTrackCircle, vector< pair< DCDCTrkHit *, double > > &locDeltaPhis)
TEllipse * e
void Link_SuperLayers_FromAxial(vector< DCDCTrackCircle * > &locCDCTrackCircles, unsigned int locOuterSuperLayer, unsigned int locInnerSuperLayer)
vector< int > used_cdc_indexes
const double alpha
bool CDCSortByChiSqPerNDFDecreasing(const DTrackCandidate_factory_CDC::DCDCTrackCircle *locTrackCircle1, const DTrackCandidate_factory_CDC::DCDCTrackCircle *locTrackCircle2)
void Print_TrackCircles(vector< DCDCTrackCircle * > &locCDCTrackCircles)
bool CDCSortByStereoChiSqPerNDFIncreasing(const DTrackCandidate_factory_CDC::DCDCTrackCircle *locTrackCircle1, const DTrackCandidate_factory_CDC::DCDCTrackCircle *locTrackCircle2)
jerror_t GuessChargeFromCircleFit(void)
Definition: DHelicalFit.cc:887
bool Calc_PositionAndMomentum(DCDCTrackCircle *locCDCTrackCircle, DVector3 &pos, DVector3 &mom)
bool CDCSort_Intersections(const DTrackCandidate_factory_CDC::intersection_t &locIntersection1, const DTrackCandidate_factory_CDC::intersection_t &locIntersection2)
int straw
Definition: DCDCWire.h:81
bool Check_IfPhiRangesOverlap(double locFirstSeedPhi, double locLastSeedPhi, double locTargetFirstPhi, double locTargetLastPhi)
bool Are_AllHitsOnRingShared(const DCDCSuperLayerSeed *locCDCSuperLayerSeed, int locRing) const
DGeometry * GetDGeometry(unsigned int run_number)
void Get_Hits(vector< DCDCTrkHit * > &locHits) const
void Create_NewCDCSuperLayerSeeds(DCDCTrackCircle *locCDCTrackCircle)
bool Calc_StereoPosition(const DCDCWire *wire, const DHelicalFit *fit, DVector3 &pos, double &var_z, double &locPhiStereo, double d=0.0)
void Add_LastSuperLayerSeed(DCDCSuperLayerSeed *locSuperLayerSeed)
void Recycle_DCDCTrackCircle(DCDCTrackCircle *locCDCTrackCircle)
bool SearchFor_SpiralTurn_TwoSeedsSharingManyHits(DCDCSuperLayerSeed *locSuperLayerSeed1, DCDCSuperLayerSeed *locSuperLayerSeed2)
void Truncate_TrackCircles(vector< DCDCTrackCircle * > &locCDCTrackCircles)
jerror_t FitCircle(void)
Definition: DHelicalFit.cc:385
void Drop_IncompleteGroups(vector< DCDCTrackCircle * > &locCDCTrackCircles)
void Find_SuperLayerSeeds(vector< DCDCTrkHit * > &locSuperLayerHits, unsigned int locSuperLayer)
bool Build_TrackCircles(vector< DCDCTrackCircle * > &locCDCTrackCircles)
int bitcount(unsigned int n)
void Reject_DefiniteSpiralArms(vector< DCDCTrackCircle * > &locCDCTrackCircles)
&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)
double sqrt(double)
DVector3 Find_IntersectionBetweenSuperLayers(const DCDCSuperLayerSeed *locInnerSuperLayerSeed, const DCDCSuperLayerSeed *locOuterSuperLayerSeed)
void Reset(void)
Definition: DHelicalFit.cc:73
double sin(double)
bool Link_SuperLayers_FromStereo_ToAxial(vector< DCDCTrackCircle * > &locCDCTrackCircles, unsigned int locOuterSuperLayer, unsigned int locInnerSuperLayer)
float chisq
Chi-squared for the track (not chisq/dof!)
void FindSenseOfRotation(void)
jerror_t evnt(JEventLoop *locEventLoop, uint64_t eventnumber)
Called every event.
jerror_t FitCircleStraightTrack()
Definition: DHelicalFit.cc:762
double FindMinimumChisq(double a, double b, double c, double &lambda)
vector< vector< DCDCRingSeed > >::iterator ringiter
bool Attempt_SeedLink(DCDCSuperLayerSeed *locSuperLayerSeed1, DCDCSuperLayerSeed *locSuperLayerSeed2)
DCDCSuperLayerSeed * Get_Resource_CDCSuperLayerSeed(void)
void BracketMinimumChisq(double &a, double &b, double &c, double &chi2a, double &chi2b, double &chi2c)
#define COUNT(x, c)
void Absorb_TrackCircle(const DCDCTrackCircle *locTrackCircle)
int ring
Definition: DCDCWire.h:80
bool Find_ThetaZ_Regression(const DHelicalFit *locFit, const vector< DCDCTrkHit * > &locStereoHits, double &locTheta, double &locZ, double &locChiSqPerNDF)
bool Select_CDCSuperLayerSeeds(DCDCTrackCircle *locCDCTrackCircle, bool locFinalPassFlag)
bool Find_ThetaZ(const DHelicalFit *locFit, const vector< DCDCTrkHit * > &locStereoHits, double &locTheta, double &locZ, double &locChiSqPerNDF)
void Set_HitBitPattern_All(vector< DCDCTrackCircle * > &locCDCTrackCircles)
void Select_ThetaZStereoHits(const DCDCTrackCircle *locCDCTrackCircle, int locInnerSeedSeriesIndex, int locOuterSeedSeriesIndex, bool locFinalPassFlag, vector< DCDCTrkHit * > &locComboHits)
bool SearchFor_SpiralTurn_SingleSeed(DCDCSuperLayerSeed *locSuperLayerSeed)
#define SHFT(w, x, y, z)
#define BeamRMS
int Ndof
Number of degrees of freedom in the fit.
void Fit_Circles(vector< DCDCTrackCircle * > &locCDCTrackCircles, bool locFitOnlyIfNullFitFlag, bool locAddStereoLayerIntersectionsFlag, bool locFitDuringLinkingFlag=false)
void Set_HitBitPattern_Axial(vector< DCDCTrackCircle * > &locCDCTrackCircles)
bool CDCSort_DeltaPhis(const pair< DTrackCandidate_factory_CDC::DCDCTrkHit *, double > &locDeltaPhiPair1, const pair< DTrackCandidate_factory_CDC::DCDCTrkHit *, double > &locDeltaPhiPair2)
void setPosition(const DVector3 &aPosition)
double MinDist2(const DCDCRingSeed &locInnerRingSeed, const DCDCRingSeed &locOuterRingSeed)
TDirectory * dir
Definition: bcal_hist_eff.C:31
float phi
Definition: DCDCWire.h:78
double zmin
TH2F * temp
void Link_SuperLayers_FromStereo_ToStereo(vector< DCDCTrackCircle * > &locCDCTrackCircles, unsigned int locOuterSuperLayer, unsigned int locInnerSuperLayer)
bool GetTargetZ(double &z_target) const
z-location of center of target
Definition: DGeometry.cc:1933
union @6::@8 u
float stereo
Definition: DCDCWire.h:82
void Filter_TrackCircles_Axial(vector< DCDCTrackCircle * > &locCDCTrackCircles)
bool CDCSortByRdecreasing(const DTrackCandidate_factory_CDC::DCDCTrkHit *hit1, const DTrackCandidate_factory_CDC::DCDCTrkHit *hit2)
TH1F * hist[Idx+1]
Definition: readhist.C:10
double MinDeltaPhi(const vector< DCDCTrkHit * > &locInnerSeedHits, const vector< DCDCTrkHit * > &locOuterSeedHits)
int GetNhits() const
Definition: DHelicalFit.h:133
Particle_t
Definition: particleType.h:12