// $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 #include #define BeamRMS 0.1 #define Z_TARGET 65.0 #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_SEED_HITS = 2; MAX_SUBSEED_LINKED_HITS = 12; MAX_RING_SUBSEED_HITS = 4; MAX_HIT_DIST = 4.0; // cm MAX_SEED_TIME_DIFF = 450.0; // ns MAX_CDC_MATCH_ANGLE = 20.0; // degrees MAX_FDC_MATCH_ANGLE = 40.0; // degrees MAX_SEED_LINK_ANGLE = M_PI/6.0*57.3; // degrees TARGET_Z_MIN = 50.0; TARGET_Z_MAX = 80.0; DEBUG_LEVEL = 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); // 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) { 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_FDC_MATCH_ANGLE", MAX_FDC_MATCH_ANGLE); gPARMS->SetDefaultParameter("TRKFIND:MAX_SEED_LINK_ANGLE", MAX_SEED_LINK_ANGLE); gPARMS->SetDefaultParameter("TRKFIND:DEBUG_LEVEL", DEBUG_LEVEL); 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); // 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); // Fit linked seeds to circles for(unsigned int i=0; i5)_DBG_<<"-- Starting fit for seed "<3)_DBG_<<"----- Seed "<3)_DBG_<<"seed.fit.phi="<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); } } } // The following is from a fit of ratio of thrown to reconstructed // transverse momentum vs. theta for the 1400A field //double par[] = {0.984463, 0.150759, -0.414933, 0.257472, -0.055801}; //double theta = seed.theta; //double ff = par[0]+theta*(par[1]+theta*(par[2]+theta*(par[3]+theta*par[4]))); double p_trans = seed.fit.p_trans*seed.FindAverageBz(loop)/2.0; double phi = seed.fit.phi; double q = seed.fit.q; double theta = seed.theta; //Make a track candidate from results DTrackCandidate *can = new DTrackCandidate; DVector3 pos, mom; pos.SetXYZ(0.0, 0.0, seed.z_vertex); mom.SetMagThetaPhi(p_trans/sin(theta), theta, phi); //pos.SetXYZ(0.0, 0.0, 65.0); //mom.SetMagThetaPhi(p_trans, M_PI/2.0, phi); can->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;nAddAssociatedObject(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 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 } //------------------ // 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; 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-=2.0*M_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>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; seed.fit.AddHitXYZ(pos.X(), pos.Y(),pos.Z()); } // Add in any FDC hits for(unsigned int j=0; jx, hit->y, hit->wire->origin.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 || 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="<x - x0; double dy = hit->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 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="<1)_DBG_<<" looking for DFDCPseudo hit to add to seed "< fdchits; eventLoop->Get(fdchits); vector fdc1_hits_matched; for(unsigned int j=0; jwire->layer>6)continue; // only interested in 1st package DVector2 sl1(sl1_wire->origin.X(), sl1_wire->origin.Y()); DVector2 fdc1(fdchit->x, fdchit->y); double a = sl1.DeltaPhi(fdc1); if(fabs(a)3)_DBG_<<"Potential match of FDC to CDC candidate delta phi="<0){ if(DEBUG_LEVEL>1)_DBG_<<"Matched "<1)_DBG_<<" no matching stray hits found to add to seed "< &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_<<"alpha1="<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 ? +2.0*M_PI:0.0; double phi_lo = seed.fit.q>0.0 ? 0.0:-2.0*M_PI; while(mytrkhit.phi_stereophi_hi){ mytrkhit.phi_stereo-=2.0*M_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)); r.push_back(R); z.push_back(trkhit->z_stereo); } for(unsigned int i=0; ix,2.0) + pow((double)fdchit->y,2.0)); r.push_back(R); z.push_back(fdchit->wire->origin.Z()); } // 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; DMagneticFieldMap *bfield = dapp->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; } // If there are no stereo hits, fall back on available FDC hits for (unsigned int i=0; iGetField(hit->x, hit->y, hit->wire->origin(2), Bx, By, Bz); Bz_sum += Bz; } return Bz_sum/(double)(stereo_hits.size()+fdchits.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; DVector3 beam(0,0,65.); intersections.push_back(beam); // CDC stereo hits 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); if(DEBUG_LEVEL>5)_DBG_<<"Adding CDC hit "<