// $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){ 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 (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){ //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); } } } } if (FILTER_SEEDS){ //Look for seeds that share hits and mark a seed as invalid if it shares more //than a certain fraction (to be determined) of hits with another seed and the //chisq/df from the circle fit is worse than that of the other fit by a //certain amount unsigned int numwords=seeds[0].HitBitPattern.size(); for(unsigned int i=0; i0.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); 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="<15){ _DBG_<<" --- wire->udir X, Y, Z = "<udir.X()<<", "<udir.Y()<<", "<udir.Z()<z_stereo="<z_stereo<<" trkhit->y_stereo="<y_stereo<<" trkhit->x_stereo="<x_stereo<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<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(d2GetBz(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 jerror_t DTrackCandidate_factory_CDC::FindThetaZRegression(DCDCSeed &seed){ if(DEBUG_LEVEL>3)_DBG_<<"Finding theta and z via linear regression method."<intersections; // CDC stereo hits for (unsigned int m=0;mx_stereo*trkhit->x_stereo+trkhit->y_stereo*trkhit->y_stereo; //DVector3_with_perp intersection; intersection_t intersection; DVector3 N=seed.fit.normal; //double c0=seed.fit.c_origin; double A=seed.fit.c_origin+R2*N.Z(); double B=N.Perp(); double C=B*R2-A*A; if (C>=0) { double sqrtC=sqrt(C); double x1=(-N.X()*A+N.Y()*sqrtC)/B; double y1=(-N.Y()*A-N.X()*sqrtC)/B; double x2=(-N.X()*A-N.Y()*sqrtC)/B; double y2=(-N.Y()*A+N.X()*sqrtC)/B; if (fabs(trkhit->y_stereo-y1)y_stereo-y2)){ //intersection.SetX(x1); //intersection.SetY(y1); intersection.x=x1; intersection.y=y1; intersection.perp2=x1*x1+y1*y1; } else{ //intersection.SetX(x2); //intersection.SetY(y2); intersection.x=x2; intersection.y=y2; intersection.perp2=x2*x2+y2*y2; } //intersection.SetZ(trkhit->z_stereo); intersection.z=trkhit->z_stereo; intersection.var_z=trkhit->var_z; intersections.push_back(intersection); if(DEBUG_LEVEL>5) _DBG_<<"Adding CDC hit "<VERTEX_Z_MAX || z05)_DBG_<<"Fit failed for theta-z via regressionz 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 dphi=M_PI_2-phi_minus-seed.fit.phi; while (dphi>M_TWO_PI) dphi-=M_TWO_PI; while (dphi<-M_TWO_PI) dphi+=M_TWO_PI; if (dphi<-M_PI) dphi+=M_TWO_PI; if (dphi>M_PI) dphi-=M_TWO_PI; pos.SetXYZ(x_minus,y_minus,seed.z_vertex+seed.fit.q*rc*dphi*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 dphi=M_PI_2-phi_plus-seed.fit.phi; while (dphi>M_TWO_PI) dphi-=M_TWO_PI; while (dphi<-M_TWO_PI) dphi+=M_TWO_PI; if (dphi<-M_PI) dphi+=M_TWO_PI; if (dphi>M_PI) dphi-=M_TWO_PI; pos.SetXYZ(x_plus,y_plus,seed.z_vertex+seed.fit.q*rc*dphi*tanl); mom.SetXYZ(pt*sin(phi_plus),pt*cos(phi_plus),pt*tanl); } return NOERROR; }