// $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 1.0 #define EPS 1e-3 #ifndef M_TWO_PI #define M_TWO_PI 6.28318530717958647692 #endif #include "DTrackCandidate_factory_CDC.h" #define TWO(c) (0x1u << (c)) #define MASK(c) ((unsigned int)(-1)) / (TWO(TWO(c)) + 1u) #define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c)) inline int bitcount (unsigned int n) { n = COUNT(n, 0) ; n = COUNT(n, 1) ; n = COUNT(n, 2) ; n = COUNT(n, 3) ; n = COUNT(n, 4) ; /*n = COUNT(n, 5) ; for 64-bit integers */ return n ; } class DVector3_with_perp:public DVector3 { public: DVector3_with_perp():DVector3(){CalcPerp();} DVector3_with_perp(double x, double y, double z):DVector3(x,y,z){CalcPerp();} double CalcPerp(void){ perp = Perp(); return perp; } double perp; }; inline bool SortIntersections(const intersection_t &a,const intersection_t &b){ if (a.perp2hit->wire->ring == hit2->hit->wire->ring){ return hit1->hit->wire->straw < hit2->hit->wire->straw; } return hit1->hit->wire->ring > hit2->hit->wire->ring; } inline 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; } inline 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; } inline 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_ALLOWED_CDC_HITS = 10000; MAX_SUBSEED_STRAW_DIFF = 1; MIN_SEED_HITS = 2; MAX_SUBSEED_LINKED_HITS = 12; MAX_RING_SUBSEED_HITS = 4; MAX_HIT_DIST = 4.0; // cm MAX_SEED_TIME_DIFF = 1000.0; // ns MAX_CDC_MATCH_ANGLE = 20.0; // degrees MAX_SEED_LINK_ANGLE = M_PI/6.0*57.3; // degrees TARGET_Z_MIN = 50.0; TARGET_Z_MAX = 80.0; TARGET_Z=65.0; DEBUG_LEVEL = 0; VERTEX_Z_MIN=-100.0; VERTEX_Z_MAX=+200.0; FILTER_SEEDS=false; // 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); // Set the layer numbers defining the superlayer boundaries superlayer_boundaries.push_back( 4); superlayer_boundaries.push_back(12); superlayer_boundaries.push_back(16); superlayer_boundaries.push_back(24); superlayer_boundaries.push_back(28); return NOERROR; } //------------------ // brun //------------------ jerror_t DTrackCandidate_factory_CDC::brun(JEventLoop *eventLoop, int runnumber) { DApplication* dapp=dynamic_cast(eventLoop->GetJApplication()); bfield = dapp->GetBfield(); // get the geometry const DGeometry *geom = dapp->GetDGeometry(runnumber); geom->GetTargetZ(TARGET_Z); double zrange; geom->GetTargetLength(zrange); TARGET_Z_MIN=TARGET_Z-0.5*zrange; TARGET_Z_MAX=TARGET_Z+0.5*zrange; gPARMS->SetDefaultParameter("TRKFIND:MAX_ALLOWED_CDC_HITS", MAX_ALLOWED_CDC_HITS); gPARMS->SetDefaultParameter("TRKFIND:MAX_SUBSEED_STRAW_DIFF", MAX_SUBSEED_STRAW_DIFF); gPARMS->SetDefaultParameter("TRKFIND:MIN_SEED_HITS", MIN_SEED_HITS); gPARMS->SetDefaultParameter("TRKFIND:MAX_SUBSEED_LINKED_HITS", MAX_SUBSEED_LINKED_HITS); gPARMS->SetDefaultParameter("TRKFIND:MAX_RING_SUBSEED_HITS", MAX_RING_SUBSEED_HITS); gPARMS->SetDefaultParameter("TRKFIND:MAX_HIT_DIST", MAX_HIT_DIST); gPARMS->SetDefaultParameter("TRKFIND:MAX_SEED_TIME_DIFF", MAX_SEED_TIME_DIFF); gPARMS->SetDefaultParameter("TRKFIND:MAX_CDC_MATCH_ANGLE", MAX_CDC_MATCH_ANGLE); gPARMS->SetDefaultParameter("TRKFIND:MAX_SEED_LINK_ANGLE", MAX_SEED_LINK_ANGLE); gPARMS->SetDefaultParameter("TRKFIND:DEBUG_LEVEL", DEBUG_LEVEL); gPARMS->SetDefaultParameter("TRKFIND:FILTER_SEEDS",FILTER_SEEDS); 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) { for(unsigned int i=0; i seeds_sl5; vector seeds_sl3; vector seeds_sl1; if(DEBUG_LEVEL>3)_DBG_<<"========= SL5 =========="<3)_DBG_<<"========= SL3 =========="<3)_DBG_<<"========= SL1 =========="< seeds_tmp, seeds_tmpSL5,seeds_tmpSL3_SL5,seeds; LinkSeeds(seeds_sl5, seeds_sl3, seeds_tmp, MAX_SUBSEED_LINKED_HITS); // Put aside the seeds that only have hits in SL5 for (unsigned int i=0;ihit->wire->ring>24){ seeds_tmpSL5.push_back(seeds_tmp[i]); } else{ seeds_tmpSL3_SL5.push_back(seeds_tmp[i]); } } // Link seeds between SL1 and SL3+SL5 LinkSeeds(seeds_tmpSL3_SL5, seeds_sl1, seeds, 2*MAX_SUBSEED_LINKED_HITS); // Insert the SL5 seeds into the full list of seeds seeds.insert(seeds.begin(),seeds_tmpSL5.begin(),seeds_tmpSL5.end()); // Check to add lone hits in SL3 to seeds with only SL1 hits PickupUnmatched(seeds); // Drop seeds containing hits from only a single axial superlayer besides SL1 DropIncompleteSeeds(seeds); if (seeds.size()>0){ // Create vectors to store bit pattern of hits used by the seeds for (unsigned int i=0;i5)_DBG_<<"-- Starting fit for seed "<3)_DBG_<<"----- Seed "<3)_DBG_<<"seed.fit.phi="<hit->wire->ring<5); if (first_stereo_count==0 && max_axial_ring_in_first_superlayer){ seed.valid=false; continue; } // Go on to the next set of stereo layers AddStereoHits(cdchits_by_superlayer[4-1], seed); // If no stereo hits were found for this seed, then // we can't fit it. if(seed.stereo_hits.size()==0){ seed.valid=false; continue; } if (max_axial_ring_in_first_superlayer){ // If we only have axial hits in the first layer, use the point of // closest approach between two adjacent stereo straws that have // opposite-sign stereo angles as another approximate point on the // circle. if (seed.stereo_hits[0].hit->wire->ring>8){ for (unsigned int is=0;iswire->ring>8 && seed.stereo_hits[inext].hit->wire->ring<=8){ DVector3 u0=seed.stereo_hits[is].hit->wire->origin; DVector3 udir=seed.stereo_hits[is].hit->wire->udir; DVector3 v0=seed.stereo_hits[inext].hit->wire->origin; DVector3 vdir=seed.stereo_hits[inext].hit->wire->udir; DVector3 diff=u0-v0; double u_dot_v=udir.Dot(vdir); double u_dot_diff=udir.Dot(diff); double v_dot_diff=vdir.Dot(diff); double scale=1./(1.-u_dot_v*u_dot_v); double ul=scale*(u_dot_v*v_dot_diff-u_dot_diff); double vl=scale*(v_dot_diff-u_dot_v*u_dot_diff); DVector3 pos=0.5*(u0+ul*udir+v0+vl*vdir); DHelicalFit myfit(seed.fit); myfit.AddHitXYZ(pos.X(), pos.Y(),pos.Z()); if (myfit.FitCircleRiemann()==NOERROR){ seed.fit.x0=myfit.x0; seed.fit.y0=myfit.y0; seed.fit.r0=myfit.r0; //seed.fit.p_trans=myfit.p_trans; seed.fit.p_trans=2.0*0.003*myfit.r0; // with |Bz|=2.0, will be fixed later double myphi=atan2(myfit.y0,myfit.x0)-M_PI_2; if(myphi<0)myphi+=M_TWO_PI; if(myphi>=M_TWO_PI)myphi-=M_TWO_PI; seed.fit.phi=myphi; for (unsigned int js=0;jshit->wire; double var_z=0.; if (GetStereoPosition(wire,seed.fit,pos,var_z)==NOERROR){ stereo->x_stereo=pos.X(); stereo->y_stereo=pos.Y(); stereo->z_stereo=pos.Z(); stereo->var_z=var_z; // Compute phi for the stereo wire DVector2 R(seed.fit.x0, seed.fit.y0); stereo->phi_stereo = atan2(stereo->y_stereo-R.Y(), stereo->x_stereo-R.X()); R*=-1.0; // make R point from center of circle to beamline instead of other way around if(DEBUG_LEVEL>15){ _DBG_<<" -- ring="<ring <<" trkhit->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 ? +M_TWO_PI:0.0; double phi_lo = seed.fit.q>0.0 ? 0.0:-M_TWO_PI; while(stereo->phi_stereophi_stereo+=M_TWO_PI; } while(stereo->phi_stereo>phi_hi){ stereo->phi_stereo-=M_TWO_PI; } } } } break; } } } } if (FindThetaZRegression(seed)!=NOERROR){ // If the linear regression doesn't work try the histogramming method // Fit stereo hits to get theta and vertex z position FindThetaZ(seed); if(!seed.valid){ // reset the valid flag seed.valid=true; //continue; // Assume that the track came from one end or the other // of the target and use a point in one of the stereo // layers to estimate tanl if (seed.z_vertex>TARGET_Z_MAX) seed.z_vertex=TARGET_Z_MAX; else seed.z_vertex=TARGET_Z_MIN; double x=seed.stereo_hits[0].x_stereo; double y=seed.stereo_hits[0].y_stereo; double ratio=sqrt(x*x+y*y)/2./seed.fit.r0; if (ratio<1.){ double tanl=(seed.stereo_hits[0].z_stereo-seed.z_vertex)/ (2.*seed.fit.r0*asin(ratio)); seed.theta=M_PI_2-atan(tanl); } //_DBG_ << " FindThetaZ failed" <0.9 || (hitratio>0.5 && fabs(chisq_nu_1-chisq_nu_2)>1)){ if (chisq_nu_1 > chisq_nu_2) seeds[i].valid=false; else seeds[j].valid=false; } } } } } } // Put the good seeds in the list of cdc track candidates for(unsigned int i=0; isetPosition(pos); can->setMomentum(mom); //can->setCharge(seed.q); can->setCharge(seed.fit.q); for (unsigned int n=0;nhit; can->used_cdc_indexes.push_back(seed.hits[n]->index); can->AddAssociatedObject(cdchit); } for (unsigned int n=0;nused_cdc_indexes.push_back((seed.stereo_hits[n]).index); 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); numhits=cdctrackhits.size(); // If there are no hits, then bail now if(cdctrackhits.size()==0)return RESOURCE_UNAVAILABLE; // If there are too many hits, bail with a warning message if(cdctrackhits.size()>MAX_ALLOWED_CDC_HITS){ _DBG_<<"Too many hits in CDC ("<GetJEvent().GetEventNumber()<wire->ring*1000 + cdctrackhits[i]->wire->straw; if (newwire!=oldwire){ oldwire = newwire; // Add to "master" list DCDCTrkHit *cdctrkhit = new DCDCTrkHit; cdctrkhit->index=i; cdctrkhit->hit = cdctrackhits[i]; cdctrkhit->flags = cdctrkhit->hit->is_stereo==false ? NONE:IS_STEREO; cdctrkhit->flags |= NOISE; // (see below) cdctrkhits.push_back(cdctrkhit); // Sort into list of hits by superlayer #if 1 for(unsigned int j=0; jhit->wire->ring<=superlayer_boundaries[j]){ cdchits_by_superlayer[j].push_back(cdctrkhit); break; } } #else 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); #endif } } // 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 return NOERROR; } //------------------ // 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((unsigned int)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; jMAX_RING_SUBSEED_HITS){ if(DEBUG_LEVEL>4)_DBG_<<"rejecting subseed for having too many hits in a single layer ("< parent; parent.push_back(&subseeds[j]); LinkSubSeeds(parent, next_ring, rings.end(), seeds); } } // Mark all seeds as valid for(unsigned int i=0; i &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); }else{ if(DEBUG_LEVEL>1)_DBG_<<"rejecting seed due to too few hits (have "< &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(DEBUG_LEVEL>5)_DBG_<<"hits1.size()="< &hits2 = in_seeds2[j].hits; if(DEBUG_LEVEL>5)_DBG_<<" hits2.size()="<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-=M_TWO_PI; if(fabs(dphi*57.3)flags |= USED; } // OK, at this point we have linked the seeds and we *may* want to // to set thier "linked" flags. The linked flags are really used // to decide later if the partial seed should be promoted to // a full seed. The idea here is to only flag the seed as "linked" // if the link is strong, otherwise leaved it marked as unlinked // so it has the option of becoming another track candidate at // the next level. Note that even if we set a linked flag here, // the partial seed can still be linked with other partials in // this loop. // // The criteria for a strong link are: // 1. the number of hits in the partner's partial seed is not // greater than max_linked_hits (which is passed to us as an // argument) // 2. The minimum distance between the partial seeds' ends is less // than 3*MAX_HIT_DIST in the phi direction. // Find distance between seeds' ends double dr = fabs(pos1->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; }else{ if(DEBUG_LEVEL>3)_DBG_<<" not marking seeds as linked (dist_phi="< "<3)_DBG_<<" linked seeds "<="<3)_DBG_<<"Promoting seed "<3)_DBG_<<"Promoting seed "<hit->tdrift; if(tdrift>1000.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; jindex/numbits] |=0x1u<index%numbits; if(seed.hits[j]->flags&OUT_OF_TIME)continue; const DVector3 &pos = seed.hits[j]->hit->wire->origin; 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(TARGET_Z,BeamRMS)!=NOERROR /* || seed.fit.chisq>20*/ ){ if(DEBUG_LEVEL>3)_DBG_<<"Riemann fit failed. Attempting regression fit..."<20*/ ){ if(DEBUG_LEVEL>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>15)_DBG_<<"dist="<3)_DBG_<<"Circle fit: Nhits="<3)_DBG_<<"Rejected circle fit due to minority of hits on track (N="< &seeds) { /// Look for single hits in superlayers that did not have enough /// neighbors to make seeds of their own, but could be part of /// a seed made in another axial superlayer. This is mainly here /// to address tracks that have a single hit in SL3 that is /// otherwise discarded. Seeds with only hits in SL1 often /// don't enough information to form a good candidate so we try /// and pick up these single hits in order to get a good handle /// on the candidate. // Loop through seeds, looking for ones with only SL1 hits for(unsigned int i=0; i &hits = seeds[i].hits; if(hits.size()<1)continue; bool has_non_SL1_hit = false; for(unsigned int j=0; jhit->wire->ring>superlayer_boundaries[0]){ has_non_SL1_hit = true; break; } } if(has_non_SL1_hit)continue; if(DEBUG_LEVEL>1)_DBG_<<"seed "<hit->wire; for(unsigned int j=0; jflags&USED)continue; if(sl3_hit->hit->wire->ring<=superlayer_boundaries[1])continue; if(sl3_hit->hit->wire->ring>superlayer_boundaries[2])continue; //double a = sl1_wire->origin.Angle(sl3_hit->hit->wire->origin); double a=sl1_wire->sdir.Angle(sl3_hit->hit->wire->sdir); if(fabs(a)flags |= USED; hits.push_back(sl3_hit); added_hit = true; if(DEBUG_LEVEL>1)_DBG_<<"Adding stray SL3 hit to SL1 seed a="< &seeds) { /// Look for seeds that have hits only in SL3 or only in SL5 and drop them. int iSL1_lo = 1; int iSL1_hi = superlayer_boundaries[0]; int iSL3_lo = superlayer_boundaries[1]+1; int iSL3_hi = superlayer_boundaries[2]; int iSL5_lo = superlayer_boundaries[3]+1; int iSL5_hi = superlayer_boundaries[3]; // Loop through seeds, looking for ones with only SL1 hits for(unsigned int i=0; i &hits = seeds[i].hits; if(hits.size()<1)continue; bool has_SL1_hit = false; bool has_SL3_hit = false; bool has_SL5_hit = false; for(unsigned int j=0; jhit->wire->ring; if(ringiSL1_hi)has_SL1_hit = true; if(ringiSL3_hi)has_SL3_hit = true; if(ringiSL5_hi)has_SL5_hit = true; if(has_SL1_hit)break; } if(has_SL1_hit)continue; if(has_SL3_hit && has_SL5_hit)continue; // Seed contains hits only from superlayer 3 or only from superlayer 5 // Flag the seed as invalid so it is ignored later seeds[i].valid = false; if(DEBUG_LEVEL>1)_DBG_<<"Dropping seed "< &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="<0.0 ? +M_TWO_PI:0.0; double phi_lo = seed.fit.q>0.0 ? 0.0:-M_TWO_PI; while(mytrkhit.phi_stereophi_hi){ mytrkhit.phi_stereo-=M_TWO_PI; } mytrkhit.flags |= VALID_STEREO; seed.stereo_hits.push_back(mytrkhit); if(DEBUG_LEVEL>10)_DBG_<<"Adding CDC stereo hit: ring="<wire->ring<<" straw="<wire->straw<15){ _DBG_<<" --- wire->udir X, Y, Z = "<udir.X()<<", "<udir.Y()<<", "<udir.Z()<z_stereo=" <y_stereo=" <x_stereo=" <5)_DBG_<<"Num stereo hits: "<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)); double R=sqrt(trkhit->x_stereo*trkhit->x_stereo +trkhit->y_stereo*trkhit->y_stereo); r.push_back(R); z.push_back(trkhit->z_stereo); } // Add center of target as a point to constrain the fit a little more r.push_back(0.0); z.push_back(TARGET_Z); // 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(d21.) return; double dphi=2.*asin(ratio); // Positive and negative changes in phi double phiplus=Phi1+dphi; double phiminus=Phi1-dphi; DVector2 plus(xc+rc*cos(phiplus),yc+rc*sin(phiplus)); DVector2 minus(xc+rc*cos(phiminus),yc+rc*sin(phiminus)); // Compute differences double d2plus=(plus-xy2).Mod2(); double d2minus=(minus-xy2).Mod2(); // Guess for charge based on differences double my_q=1.; if (d2minusM_PI) fit.phi-=M_TWO_PI; } } //------------------ // DCDCSeed::FindAverageBz //------------------ double DTrackCandidate_factory_CDC::DCDCSeed::FindAverageBz( const DMagneticFieldMap *bfield ) { //return 2.0; if(!bfield)return 0.0; double Bz_sum=0.0; for(unsigned int i=0; iGetBz(hit->x_stereo,hit->y_stereo, hit->z_stereo); } return Bz_sum/(double)(stereo_hits.size()); } //------------------ // FindThetaZRegression //------------------ // Linear regression to find tan(lambda) and z_vertex. // This method assumes that there are errors in both the z positions and // the arc lengths. // Algorithm from Numerical Recipes in C (2nd. ed.), pp. 668-669. jerror_t DTrackCandidate_factory_CDC::FindThetaZRegression(DCDCSeed &seed){ if(DEBUG_LEVEL>3)_DBG_<<"Finding theta and z via linear regression method."<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; // CDC stereo hits int old_ring=-1; for (unsigned int m=0;mhit->wire->ring!=old_ring){ //DVector3_with_perp intersection; intersection_t intersection; intersection.x=trkhit->x_stereo; intersection.y=trkhit->y_stereo; intersection.perp2=intersection.x*intersection.x+intersection.y*intersection.y; intersection.z=trkhit->z_stereo; intersection.var_z=trkhit->var_z; intersections.push_back(intersection); } old_ring=trkhit->hit->wire->ring; } // Now, sort the entries sort(intersections.begin(),intersections.end(),SortIntersections); // Compute the arc lengths between the origin in x and y and (xi,yi) vectorarclengths(intersections.size()); vectorratios(intersections.size()); double xc=myfit->x0; double yc=myfit->y0; double rc=myfit->r0; double two_rc=2.*rc; // Find POCA to beam line double myphi=atan2(yc,xc); double y0=yc-rc*sin(myphi); double x0=xc-rc*cos(myphi); // Arc length to first measurement double diffx=intersections[0].x-x0; double diffy=intersections[0].y-y0; double chord=sqrt(diffx*diffx+diffy*diffy); double ratio=chord/two_rc; double s=(ratio<1.)?two_rc*asin(ratio):M_PI_2*two_rc; arclengths[0]=s; ratios[0]=ratio; // Find arc lengths for the rest of the stereo hits for (unsigned int m=1;m0.999) return VALUE_OUT_OF_RANGE; double ds=two_rc*asin(ratio); s+=ds; arclengths[m]=s; ratios[m]=ratio; } //Linear regression to find z0, tanl double tanl=0.,z0=0.; if (arclengths.size()>2){ // Do fit only if have more than one measurement DCDCLineFit fit; unsigned int n=fit.n=intersections.size(); fit.s.resize(n); fit.var_s.resize(n); fit.z.resize(n); fit.var_z.resize(n); fit.w.resize(n); // Find average variances for z and s double avg_var_s=0.,avg_var_z=0.; double var_r=1.6*1.6/12.; // assume cell size for (unsigned int m=0;m5) _DBG_<<"Using CDC hit "<VERTEX_Z_MAX || z05)_DBG_<<"Fit failed for theta-z via regression value out of target range (z="<EPS){ phi_plus*=-1.; y_plus=yc+rc*sin(phi_plus); } if (fabs(r2-r2_minus)>EPS){ phi_minus*=-1.; y_minus=yc+rc*sin(phi_minus); } // Choose phi- or phi+ depending on proximity to one of the cdc hits double xwire=seed.hits[0]->hit->wire->origin.x(); double ywire=seed.hits[0]->hit->wire->origin.y(); double dx=x_minus-xwire; double dy=y_minus-ywire; double d2_minus=dx*dx+dy*dy; dx=x_plus-xwire; dy=y_plus-ywire; double d2_plus=dx*dx+dy*dy; if (d2_plus>d2_minus){ phi_minus*=-1.; if (seed.fit.q<0) phi_minus+=M_PI; double myphi=atan2(yc,xc); double xv=xc-rc*cos(myphi); double yv=yc-rc*sin(myphi); double dx=x_minus-xv; double dy=y_minus-yv; double chord=sqrt(dx*dx+dy*dy); double two_rc=2.*rc; double ratio=chord/two_rc; double ds=(ratio<1.)?(two_rc*asin(ratio)):(two_rc*M_PI_2); pos.SetXYZ(x_minus,y_minus,seed.z_vertex+ds*tanl); mom.SetXYZ(pt*sin(phi_minus),pt*cos(phi_minus),pt*tanl); } else{ phi_plus*=-1.; if (seed.fit.q<0) phi_plus+=M_PI; double myphi=atan2(yc,xc); double xv=xc-rc*cos(myphi); double yv=yc-rc*sin(myphi); double dx=x_plus-xv; double dy=y_plus-yv; double chord=sqrt(dx*dx+dy*dy); double two_rc=2.*rc; double ratio=chord/two_rc; double ds=(ratio<1.)?(two_rc*asin(ratio)):(two_rc*M_PI_2); pos.SetXYZ(x_plus,y_plus,seed.z_vertex+ds*tanl); mom.SetXYZ(pt*sin(phi_plus),pt*cos(phi_plus),pt*tanl); } return NOERROR; } //------------------------------------------------------------------------- // Routines for fitting a line to the stereo data //------------------------------------------------------------------------- // Compute the chi^2 for a line fit given errors in both s and z. Also // computes current best guess for the scaled intercept z0. // Taken from Numerical Recipes in C (2nd ed.), p. 670. double DTrackCandidate_factory_CDC::DCDCLineFit::ChiXY(double lambda){ double tanl=tan(lambda); double sumw=0.,avg_s=0.,avg_z=0.,my_chi2=0.; for (unsigned i=0;i=0.0 ? fabs(x):-fabs(x)) void DTrackCandidate_factory_CDC ::DCDCLineFit::BracketMinimumChisq(double &a,double &b,double &c, double &chi2a,double &chi2b, double &chi2c){ const double GOLD=1.618034; const double GLIMIT=100.0; chi2a=ChiXY(a); chi2b=ChiXY(b); double chi2u=0.; if (chi2b>chi2a){ double dummy=0.; SHFT(dummy,a,b,dummy); SHFT(dummy,chi2b,chi2a,dummy); } c=b+GOLD*(b-a); chi2c=ChiXY(c); while (chi2b>chi2c){ double r=(b-a)*(chi2b-chi2c); double q=(b-c)*(chi2b-chi2a); double q_minus_r=q-r; double fabs_q_minus_r=fabs(q_minus_r); double max=(fabs_q_minus_r>1.e-20)?fabs_q_minus_r:1.e-20; double u=b-((b-c)*q-(b-a)*r)/(2.*SIGN(max,q_minus_r)); double ulim=b+GLIMIT*(c-b); if ((b-u)*(u-c)>0.0){ chi2u=ChiXY(u); if (chi2uchi2b){ c=u; chi2c=chi2u; return; } u=c+GOLD*(c-b); chi2u=ChiXY(u); } else if ((c-u)*(u-ulim)>0.0){ chi2u=ChiXY(u); if (chi2u=0.0){ u=ulim; chi2u=ChiXY(u); } else{ u=c+GOLD*(c-b); chi2u=ChiXY(u); } SHFT(a,b,c,u); SHFT(chi2a,chi2b,chi2c,chi2u); } } // Use Brent's algorithm to find the "true" (within tolerance) minimum chi^2 // after bracketting. Taken from Numerical Recipes in C (2nd. Ed.), pp. 404-405. double DTrackCandidate_factory_CDC ::DCDCLineFit::FindMinimumChisq(double ax,double bx, double cx, double &xmin){ const double CGOLD=0.3819660; double a=(axcx)?ax:cx; double x=bx,w=bx,v=bx; double fx=ChiXY(x),fv=fx,fw=fx,fu=0.; double tol=1e-3,err=0.0,d=0.,u=0.; for (int iter=1;iter<=100;iter++){ double xm=0.5*(a+b); double tol1=tol*fabs(x)+1e-10; double tol2=2.0*tol1; if (fabs(x-xm)<=(tol2-0.5*(b-a))){ xmin=x; return fx; } if (fabs(err)>tol1){ double r=(x-w)*(fx-fv); double q=(x-v)*(fx-fw); double p=(x-v)*q-(x-w)*r; q=2.0*(q-r); if (q>0.0) p=-p; q=fabs(q); double etemp=err; err=d; if (fabs(p)>=fabs(0.5*q*etemp) || p<=q*(a-x)|| p>=q*(b-x)){ d=CGOLD*(err=(x>=xm ? a-x : b-x)); } else{ d=p/q; u=x+d; if (u-a < tol2 || b-u < tol2) d=SIGN(tol1,xm-x); } } else { d=CGOLD*(err=(x>=xm ? a-x : b-x )); } u=(fabs(d)>=tol1 ? x+d : x+SIGN(tol1,d)); fu=ChiXY(u); if (fu<=fx){ if (u>=x) a=x; else b=x; SHFT(v,w,x,u); SHFT(fv,fw,fx,fu); } else{ if (u