// $Id$ // // File: DTrackCandidate_factory_CDC.cc // Created: Thu Sep 6 14:47:48 EDT 2007 // Creator: davidl (on Darwin Amelia.local 8.10.1 i386) // #include using namespace std; #include #include #include "DHelicalFit.h" #include #include #define BeamRMS 0.1 #include "DTrackCandidate_factory_CDC.h" bool SortIntersections(const DVector3 &a,const DVector3 &b){ double Ra=a.Perp(); double Rb=b.Perp(); if (Rahit->wire->ring == hit2->hit->wire->ring){ return hit1->hit->wire->straw < hit2->hit->wire->straw; } return hit1->hit->wire->ring > hit2->hit->wire->ring; } bool CDCSortByRincreasing(DTrackCandidate_factory_CDC::DCDCTrkHit* const &hit1, DTrackCandidate_factory_CDC::DCDCTrkHit* const &hit2) { // use the ring number to sort by R return hit1->hit->wire->ring < hit2->hit->wire->ring; } bool CDCSortByZincreasing(DTrackCandidate_factory_CDC::DCDCTrkHit* const &hit1, DTrackCandidate_factory_CDC::DCDCTrkHit* const &hit2) { // use the z_stereo position to sort return hit1->z_stereo < hit2->z_stereo; } bool CDCSortByStereoPhiincreasing(DTrackCandidate_factory_CDC::DCDCTrkHit* const &hit1, DTrackCandidate_factory_CDC::DCDCTrkHit* const &hit2) { // use the z_stereo position to sort return hit1->phi_stereo < hit2->phi_stereo; } //------------------ // init //------------------ jerror_t DTrackCandidate_factory_CDC::init(void) { MAX_SUBSEED_STRAW_DIFF = 1; MIN_SUBSEED_HITS = 3; MIN_SEED_HITS = 3; MAX_SUBSEED_LINKED_HITS = 12; MIN_SEED_DIST = 4.0; // cm MAX_HIT_DIST = 3.0; // cm MAX_HIT_CIRCLE_DIST = 0.8; // cm MAX_SEED_TIME_DIFF = 450.0; // ns MAX_CIRCLE_CLONE_FILTER_FRAC = 0.2; MAX_STEREO_PHI_DELTA = 0.35; // rad TARGET_Z_MIN = 50.0; TARGET_Z_MAX = 80.0; // Initialize cdchits_by_superlayer with empty vectors for each superlayer vector mt; for(int i=0; i<5; i++)cdchits_by_superlayer.push_back(mt); return NOERROR; } //------------------ // brun //------------------ jerror_t DTrackCandidate_factory_CDC::brun(JEventLoop *eventLoop, int runnumber) { gPARMS->SetDefaultParameter("TRKFIND:MAX_SUBSEED_STRAW_DIFF", MAX_SUBSEED_STRAW_DIFF); gPARMS->SetDefaultParameter("TRKFIND:MIN_SUBSEED_HITS", MIN_SUBSEED_HITS); gPARMS->SetDefaultParameter("TRKFIND:MIN_SEED_HITS", MIN_SEED_HITS); gPARMS->SetDefaultParameter("TRKFIND:MAX_SUBSEED_LINKED_HITS", MAX_SUBSEED_LINKED_HITS); gPARMS->SetDefaultParameter("TRKFIND:MIN_SEED_DIST", MIN_SEED_DIST); gPARMS->SetDefaultParameter("TRKFIND:MAX_HIT_DIST", MAX_HIT_DIST); gPARMS->SetDefaultParameter("TRKFIND:MAX_HIT_CIRCLE_DIST", MAX_HIT_CIRCLE_DIST); gPARMS->SetDefaultParameter("TRKFIND:MAX_SEED_TIME_DIFF", MAX_SEED_TIME_DIFF); gPARMS->SetDefaultParameter("TRKFIND:MAX_CIRCLE_CLONE_FILTER_FRAC", MAX_CIRCLE_CLONE_FILTER_FRAC); gPARMS->SetDefaultParameter("TRKFIND:MAX_STEREO_PHI_DELTA", MAX_STEREO_PHI_DELTA); MAX_HIT_DIST2 = MAX_HIT_DIST*MAX_HIT_DIST; return NOERROR; } //------------------ // erun //------------------ jerror_t DTrackCandidate_factory_CDC::erun(void) { return NOERROR; } //------------------ // fini //------------------ jerror_t DTrackCandidate_factory_CDC::fini(void) { return NOERROR; } //------------------ // evnt //------------------ jerror_t DTrackCandidate_factory_CDC::evnt(JEventLoop *loop, int eventnumber) { // Get CDC hits GetCDCHits(loop); // Find all seeds in all 3 axial superlayers vector seeds_sl5; vector seeds_sl3; vector seeds_sl1; if(debug_level>3)_DBG_<<"========= SL5 =========="<3)_DBG_<<"========= SL3 =========="<3)_DBG_<<"========= SL1 =========="< seeds_tmp, seeds; LinkSeeds(seeds_sl5, seeds_sl3, seeds_tmp, MAX_SUBSEED_LINKED_HITS); LinkSeeds(seeds_tmp, seeds_sl1, seeds, 2*MAX_SUBSEED_LINKED_HITS); // Fit linked seeds to circles for(unsigned int i=0; i3)_DBG_<<"----- Seed "<3)_DBG_<<"seed.fit.phi="<setPosition(pos); can->setMomentum(mom); //can->setCharge(seed.q); can->setCharge(q); for (unsigned int n=0;nhit; can->AddAssociatedObject(cdchit); } for (unsigned int n=0;nhit; can->AddAssociatedObject(cdchit); } //can->q = can->charge(); //can->phi = mom.Phi(); //can->theta = mom.Theta(); //can->p_trans = mom.Pt(); //can->p = mom.Mag(); //can->z_vertex = pos.Z(); if(debug_level>3)_DBG_<<"Final Candidate parameters: p="< cdctrackhits; loop->Get(cdctrackhits); // If there are no hits, then bail now if(cdctrackhits.size()==0)return; // If there are too many hits, bail with a warning message if(cdctrackhits.size()>200){ _DBG_<<"Too many hits in CDC! Track finding in CDC bypassed for event "<GetJEvent().GetEventNumber()<hit = cdctrackhits[i]; cdctrkhit->flags = cdctrkhit->hit->wire->stereo==0.0 ? NONE:IS_STEREO; cdctrkhit->flags |= NOISE; // (see below) // Add to "master" list cdctrkhits.push_back(cdctrkhit); // Sort into list of hits by superlayer if(cdctrkhit->hit->wire->ring<=4)cdchits_by_superlayer[0].push_back(cdctrkhit); else if(cdctrkhit->hit->wire->ring<= 12)cdchits_by_superlayer[1].push_back(cdctrkhit); else if(cdctrkhit->hit->wire->ring<=16)cdchits_by_superlayer[2].push_back(cdctrkhit); else if(cdctrkhit->hit->wire->ring<=24)cdchits_by_superlayer[3].push_back(cdctrkhit); else if(cdctrkhit->hit->wire->ring<=28)cdchits_by_superlayer[4].push_back(cdctrkhit); } // Sort the individual superlayer lists by decreasing values of R for(unsigned int i=0; iflags & NOISE))continue; // this hit already not marked for noise for(unsigned int j=0; jDist2(cdctrkhits[j]); if(d2<9.0*MAX_HIT_DIST2){ trkhit1->flags &= ~NOISE; cdctrkhits[j]->flags &= ~NOISE; break; }// if }// j }// i } //------------------ // FindSeeds //------------------ void DTrackCandidate_factory_CDC::FindSeeds(vector &hits, vector &seeds) { // Sort through hits ring by ring to find sub-seeds from neighboring wires // in the same ring. What we want is a list of sub-seeds for each ring. // Each sub-seed is a list of adjacent (or nearly adjacent) hits. Note // that hits are ordered by ring, then straw. We ignore the boundary in // straw number for now which will cause some sub-seeds to be listed as // 2 separate ones. These will be recombined later. DCDCSeed subseed; vector subseeds; vector > rings; int last_ring = -1; for(unsigned int i=0; iflags &= ~(USED|IN_SEED|IN_LINE|IN_TRACK); //if(trkhit->flags & NOISE)continue; // Check if ring number has changed. if(trkhit->hit->wire->ring != last_ring){ if(subseed.hits.size()!=0)subseeds.push_back(subseed); if(subseeds.size()!=0)rings.push_back(subseeds); if(debug_level>3)_DBG_<<" subseed hits:"<hit->wire->ring; continue; } // Check if this hit is a neighbor of the last hit added to the subseed if(abs(subseed.hits[subseed.hits.size()-1]->hit->wire->straw - trkhit->hit->wire->straw)>MAX_SUBSEED_STRAW_DIFF){ if(subseed.hits.size()!=0)subseeds.push_back(subseed); if(debug_level>3)_DBG_<<" subseed hits:"<3)_DBG_<<" subseed hits:"<3)_DBG_<<"rings: "< &subseeds = *ring; ringiter next_ring = ring; next_ring++; // Loop over subseeds of this ring for(unsigned int j=0; j parent; parent.push_back(&subseeds[j]); LinkSubSeeds(parent, next_ring, rings.end(), seeds); } } } //------------------ // LinkSubSeeds //------------------ void DTrackCandidate_factory_CDC::LinkSubSeeds(vector &parent, ringiter ring, ringiter ringend, vector &seeds) { /// Combine subseeds from layers in a single superlayer into seeds. /// /// This a a re-entrant routine (i.e. it calls itself recursively). Upon /// entry, parent contains a list of pointers to all of the subseeds /// from the rings outside of ring that are to be combined into /// a seed. This will search through all subseeds of ring and if /// any are found that can extend the parent, a copy of parent is made, /// the current subseed of this ring is added to it, and then it is /// passed on to another call to this routine. If no matches are found /// (which will necessarily be the case for the inner most layer), then /// the subseeds in parent will be combined into a single seed and /// that added to seeds. // Make sure parent has at least one subseed if(parent.size()==0){ _DBG_<<"parent has no subseeds!!"<hits[0]->hit->wire->origin.Perp(); // Loop over subseeds in this ring vector &subseeds = (*ring); ring++; // increment ring iterator to point to next level down in case we recall ouself below for(unsigned int i=0; ihit->wire->origin.Perp(); // Check if this subseed is close enough to the parent's to extend it if(parent_subseed->MinDist2(subseeds[i])<(dr*dr+MAX_HIT_DIST2)){ vector myparent = parent; myparent.push_back(&subseeds[i]); subseeds[i].linked = true; LinkSubSeeds(myparent, ring, ringend, seeds); seed_extended = true; } } } // Check if this is the end of the line. if(!seed_extended){ // This is the end of this seed. Combine the subseeds into a single // seed and add it to the list. DCDCSeed seed; seed.hits.clear(); for(unsigned int i=0; i=MIN_SEED_HITS)seeds.push_back(seed); } } //------------------ // LinkSeeds //------------------ void DTrackCandidate_factory_CDC::LinkSeeds(vector &in_seeds1, vector &in_seeds2, vector &seeds, unsigned int max_linked_hits) { /// Loop over the two input sets of seeds and compare the phi angles of /// their first and last hits. The closest combination is checked to see /// if we should combine them into a new a new seed. Any seeds from either /// list that are not linked, but have enough hits to be a full seed in and /// of themselves will be added to the seeds list. if(debug_level>3)_DBG_<<"Linking seeds: Num seeds in list 1:"< &hits1 = in_seeds1[i].hits; if(hits1.size()<1)continue; for(unsigned int j=0; j< in_seeds2.size(); j++){ vector &hits2 = in_seeds2[j].hits; if(hits2.size()<1)continue; // Find the hits from the seeds that are closest in R const DCDCWire *wire1a = hits1[0]->hit->wire; const DCDCWire *wire1b = hits1[hits1.size()-1]->hit->wire; const DCDCWire *wire2a = hits2[0]->hit->wire; const DCDCWire *wire2b = hits2[hits2.size()-1]->hit->wire; const DVector3 *pos1, *pos2; if(wire1a->ring > wire2a->ring){ // seed1 is outside seed2 pos1 = &(wire1a->ring > wire1b->ring ? wire1b:wire1a)->origin; pos2 = &(wire2a->ring < wire2b->ring ? wire2b:wire2a)->origin; }else{ // seed2 is outside seed1 pos1 = &(wire1a->ring < wire1b->ring ? wire1b:wire1a)->origin; pos2 = &(wire2a->ring > wire2b->ring ? wire2b:wire2a)->origin; } // Compare the phi values of the first and last points of the two seeds // to see if they are close enough to link. double dphi = fabs(pos1->Phi() - pos2->Phi()); while(dphi>M_PI)dphi-=2.0*M_PI; if(fabs(dphi)Perp() - pos2->Perp()); DVector3 d = *pos1 - *pos2; double dist_phi2 = d.Perp2() - dr*dr; if(dist_phi2 < 9.0*MAX_HIT_DIST2){ // Mark the seeds has having been linked. Here we do something // a little funny. We only mark a seed as linked if the other // seed doesn't have too many hits. This is because we can get // "super seeds" from a single superlayer made from many hits, // often due to crossing tracks. if(hits1.size()<=max_linked_hits)in_seeds2[j].linked = true; if(hits2.size()<=max_linked_hits)in_seeds1[i].linked = true; } if(debug_level>3)_DBG_<<" linked seeds "<="<3)_DBG_<<"Promoting seed "<3)_DBG_<<"Promoting seed "<hit->tdrift; if(tdrift>500.0){ seed.hits[j]->flags |= OUT_OF_TIME; continue; } seed.tdrift_avg += tdrift; Nin_time++; } seed.tdrift_avg /= (double)Nin_time; } } //------------------ // FitCircle //------------------ bool DTrackCandidate_factory_CDC::FitCircle(DCDCSeed &seed) { /// Do a quick fit of the 2-D projection of the axial hits /// in seed (seed should contain *only* axial hits) to a /// circle. Determine the sign of the charge (and correspondingly /// the initial phi angle) assuming that /// the majority of hits come from the outgoing part of the /// track. If the resulting circle passes within /// MAX_HIT_DIST of more the majority of hits, then true /// is returned indicating success. Otherwise, false is /// returned indicating failure and that the seed should be /// discarded. // Loop over hits in seed and add them to the seed's DHelicalFit object seed.fit.Clear(); for(unsigned int j=0; jflags&OUT_OF_TIME)continue; const DVector3 &pos = seed.hits[j]->hit->wire->origin; //double cov=seed.hits[j]->hit->dist*seed.hits[j]->hit->dist; //seed.fit.AddHitXYZ(pos.X(), pos.Y(), pos.Z(),cov,cov,0.); seed.fit.AddHitXYZ(pos.X(), pos.Y(),pos.Z()); } // Try and fit the circle using a Riemann fit. If // it fails, try a basic fit with QuickFit. if(seed.fit.FitCircleRiemann(BeamRMS)!=NOERROR){ if(debug_level>3) _DBG_<<"Riemann fit failed. Attempting regression fit..."<3)_DBG_<<"Regression circle fit failed. Trying straight line."<3)_DBG_<<"Trying straight line fit failed. Giving up."<flags&OUT_OF_TIME){ if(debug_level>6)_DBG_<<"discarding out of time hit"<hit->wire->origin.X() - x0; double dy = seed.hits[i]->hit->wire->origin.Y() - y0; double d = sqrt(dx*dx + dy*dy); if(debug_level>10)_DBG_<<"dist="<3)_DBG_<<"Circle fit: Nhits="<3)_DBG_<<"Rejected circle fit due to minority of hits on track (N="< &seeds) { /// Look for clones of seeds and flag all but one as not valid. /// Two tracks are considered clones if their trajectories are /// really close. /// The "closeness" of the two trajectories is determined using /// two methods, either of which can flag the two seeds as clones. /// /// For the first method, we use the "asymmetry" of the circle /// centers. The asymmetry is defined as the distance between /// the two circle's centers divided by the sum of the magnitudes /// of the circle's centers relative to the origin. If this is below /// some threshold (say 0.05) then the tracks are seeds are /// considered clones. /// /// For the second method, we check the distance between the /// trajectories at a point near the last hit and a point near /// one of the middle hits of one of the seeds. Since all /// seeds pass through the origin, this effectively gives 3 /// points on the circle(s). If the total sum of the distances /// between these points and the other seed's track are less than /// some small value, the two are considered clones. Note that /// currently, the choice of "middle" hits is done simply by /// looking at the N/2th hit. This may not actually be near the /// middle of the R values so a more sophisticated algorithm /// may need to be implemented later. for(unsigned int i=0; ihit->wire->origin; DVector2 alpha1(wire_pos1.X(), wire_pos1.Y()); alpha1 -= r1; alpha1 *= r1.Mod()/alpha1.Mod(); // Calculate point on seed1 at about the midpoint hit on seed1 const DVector3 &wire_pos2 = seed1.hits[seed1.hits.size()/2]->hit->wire->origin; DVector2 alpha2(wire_pos2.X(), wire_pos2.Y()); alpha2 -= r1; alpha2 *= r1.Mod()/alpha2.Mod(); for(unsigned int j=i+1; j3)_DBG_<<"asym="<3)_DBG_<<"d="<3)_DBG_<<"Filtering clone circle seed (seed1.fit.chisq="<3)_DBG_<<"alpha1="<udir X, Y, Z = "<udir.X()<<", "<udir.Y()<<", "<udir.Z()<z_stereo="<z_stereo<<" trkhit->y_stereo="<y_stereo<<" trkhit->x_stereo="<x_stereo<phi_stereo -= R.Phi(); // make angle relative to beamline // We want this to go either from 0 to +2pi for positive charge, or // 0 to -2pi for negative. double phi_hi = seed.fit.q>0.0 ? +2.0*M_PI:0.0; double phi_lo = seed.fit.q>0.0 ? 0.0:-2.0*M_PI; while(trkhit->phi_stereophi_stereo+=2.0*M_PI; while(trkhit->phi_stereo>phi_hi)trkhit->phi_stereo-=2.0*M_PI; trkhit->flags |= VALID_STEREO; seed.stereo_hits.push_back(trkhit); } // It can happen that stereo wires from nearby tracks can intersect // with the current track which, of course, screws up the parameters // later. Here, we identify some of these by looking for stereo // wire hits from the same layer ("ring") that are far enough apart // that it's unlikely they came from the same track. vector::iterator iter1 = stereo_hits.begin(); for(; iter1!=stereo_hits.end(); iter1++){ vector::iterator iter2 = iter1+1; const DCDCWire *wire1 = (*iter1)->hit->wire; for(; iter2!=stereo_hits.end(); iter2++){ const DCDCWire *wire2 = (*iter2)->hit->wire; if(wire1->ring == wire2->ring){ } } } } //------------------ // FindThetaZ //------------------ void DTrackCandidate_factory_CDC::FindThetaZ(DCDCSeed &seed) { // Decide whether to use the histogramming method or the // straight track method base on the transverse momentum if(debug_level>2)_DBG_<<"p_trans:"<2)_DBG_<<"p_trans from search:"<TARGET_Z_MAX){ if(debug_level>3)_DBG_<<"Seed z-vertex outside of target range (z="< r; vector z; for(unsigned int i=0; iflags&VALID_STEREO)continue; double R = sqrt(pow(trkhit->x_stereo,2.0) + pow(trkhit->y_stereo,2.0)); r.push_back(R); z.push_back(trkhit->z_stereo); } // Add center of target as a point to constrain the fit a little more double z_target = (TARGET_Z_MIN+TARGET_Z_MAX)/2.0; r.push_back(0.0); z.push_back(z_target); // Calculate average z and r double Ravg=0.0, Zavg=0.0; for(unsigned int i=0; i4)_DBG_<<"r="<3)_DBG_<<"theta="<Srr : theta="<3)_DBG_<<"istart="<3)_DBG_<<"istart="<Dist2(seed.hits[0]); if(hits.size()>0){ double d2 = hits[hits.size()-1]->Dist2(seed.hits[0]); if(d20){ double d2 = hits[hits.size()-1]->Dist2(seed.hits[seed.hits.size()-1]); if(d20){ double d2 = hits[0]->Dist2(seed.hits[seed.hits.size()-1]); if(d2(loop->GetJApplication()); if(!dapp)return 0.0; const DGeometry *dgeom = dapp->GetDGeometry(100); if(!dgeom)return 0.0; DMagneticFieldMap *bfield = dgeom->GetBfield(); if(!bfield)return 0.0; double Bz_sum=0.0; for(unsigned int i=0; iGetField(hit->x_stereo, hit->y_stereo, hit->z_stereo, Bx, By, Bz); Bz_sum += Bz; } return Bz_sum/(double)stereo_hits.size(); } // Linear regression to find tan(lambda) and z_vertex jerror_t DTrackCandidate_factory_CDC::FindThetaZRegression(DCDCSeed &seed){ if (seed.fit.normal.Mag()==0.) return VALUE_OUT_OF_RANGE; // Vector of intersections between the circles of the measurements and the plane intersecting the Riemann surface vectorintersections; DVector3 beam(0,0,65.); intersections.push_back(beam); for (unsigned int m=0;mx_stereo*trkhit->x_stereo+trkhit->y_stereo*trkhit->y_stereo; DVector3 intersection; DVector3 N=seed.fit.normal; double c0=seed.fit.c_origin; double A=c0+R2*N(2); double B=N(0)*N(0)+N(1)*N(1); double C=B*R2-A*A; if (C>=0) { double x1=(-N(0)*A+N(1)*sqrt(C))/B; double y1=(-N(1)*A-N(0)*sqrt(C))/B; double x2=(-N(0)*A-N(1)*sqrt(C))/B; double y2=(-N(1)*A+N(0)*sqrt(C))/B; if (fabs(trkhit->y_stereo-y1)y_stereo-y2)){ intersection(0)=x1; intersection(1)=y1; } else{ intersection(0)=x2; intersection(1)=y2; } intersection(2)=trkhit->z_stereo; intersections.push_back(intersection); } } sort(intersections.begin(),intersections.end(),SortIntersections); // Compute the arc lengths between (0,0) and (xi,yi) vectorarclengths(intersections.size()); vectorvar_z(intersections.size()); arclengths[0]=0.; double temp=1.6/sin(6.*M_PI/180.); double varz=temp*temp/12.; for (unsigned int m=1;m