// $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 "DQuickFit.h" #include "DRiemannFit.h" #include "DTrackCandidate_factory_CDC.h" bool CDCSortByRdecreasing(DTrackCandidate_factory_CDC::DCDCTrkHit* const &hit1, DTrackCandidate_factory_CDC::DCDCTrkHit* const &hit2) { // use the ring number to sort by R(decreasing) and then straw(increasing) if(hit1->hit->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; MAX_HIT_DIST2 = MAX_HIT_DIST*MAX_HIT_DIST; // 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) { 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); //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_<<"can->phi="<phi<<" phi="<theta="<theta<<" theta="< cdctrackhits; loop->Get(cdctrackhits); // If there are no hits, then bail now if(cdctrackhits.size()==0)return; // Create DCDCTrkHit objects out of these. for(unsigned int i=0; ihit = 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<= 8)cdchits_by_superlayer[1].push_back(cdctrkhit); else if(cdctrkhit->hit->wire->ring<=13)cdchits_by_superlayer[2].push_back(cdctrkhit); else if(cdctrkhit->hit->wire->ring<=17)cdchits_by_superlayer[3].push_back(cdctrkhit); else if(cdctrkhit->hit->wire->ring<=23)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 DQuickFit object for(unsigned int j=0; jflags&OUT_OF_TIME)continue; const DVector3 &pos = seed.hits[j]->hit->wire->origin; seed.fit.AddHitXYZ(pos.X(), pos.Y(), pos.Z()); } seed.fit.FitCircle(); seed.fit.GuessChargeFromCircleFit(); // Check if majority of hits are close to circle. double x0 = seed.fit.x0; double y0 = seed.fit.y0; double r0 = sqrt(x0*x0 + y0*y0); unsigned int N=0; for(unsigned int i=0; iflags&OUT_OF_TIME)continue; double dx = seed.hits[i]->hit->wire->origin.X() - x0; double dy = seed.hits[i]->hit->wire->origin.Y() - y0; double d = sqrt(dx*dx + dy*dy); if(fabs(d-r0)<=MAX_HIT_DIST)N++; } if(debug_level>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); } } //------------------ // FindThetaZ //------------------ void DTrackCandidate_factory_CDC::FindThetaZ(DCDCSeed &seed) { FindTheta(seed, TARGET_Z_MIN, TARGET_Z_MAX); FindZ(seed, seed.theta_min, seed.theta_max); // If z_vertex is not inside the target limits, then flag this // seed as invalid. if(seed.z_vertexTARGET_Z_MAX){ if(debug_level>3)_DBG_<<"Seed z-vertex outside of target range (z="<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(d2id); #if 0 printcol("%d", trackcandidate->hitid.size()); printcol("%+d", (int)trackcandidate->q); printcol("%3.3f", trackcandidate->p); printcol("%1.3f", trackcandidate->theta); printcol("%1.3f", trackcandidate->phi); printcol("%3.2f", trackcandidate->p_trans); printcol("%2.2f", trackcandidate->x0); printcol("%2.2f", trackcandidate->y0); printcol("%2.2f", trackcandidate->z_vertex); printcol("%1.3f", trackcandidate->dzdphi); #endif printrow(); } return _table; }