// $Id$ // // File: DTrack_factory_ALT2.cc // Created: Fri. Feb. 8, 2008 // Creator: davidl // #include #include #include #include #include using namespace jana; #include "GlueX.h" #include "DANA/DApplication.h" #include "DMagneticFieldStepper.h" #include "DTrackCandidate.h" #include "DTrack_factory_ALT2.h" #include "CDC/DCDCTrackHit.h" #include "FDC/DFDCPseudo.h" #include "DReferenceTrajectory.h" #include "DMCThrown.h" #define NaN std::numeric_limits::quiet_NaN() // The GNU implementation of STL includes definitions of "greater" and "less" // but the SunOS implementation does not. Since it is a bit of a pain to // define this only for SunOS, we just define "greaterthan" and use it for // all platforms/compilers. Note that this is essentially the same as the // GNU definition from stl_function.h, except it does not derive from the // templated "binary_function" class. template class greaterthan{ public: bool operator()(const T &a, const T &b) const {return a>b;} }; //------------------ // DTrack_factory_ALT2 (Constructor) //------------------ DTrack_factory_ALT2::DTrack_factory_ALT2() { // This gets allocated in brun once the bfield is known tmprt=NULL; // Define target center target = new DCoordinateSystem(); target->origin.SetXYZ(0.0, 0.0, 65.0); target->sdir.SetXYZ(1.0, 0.0, 0.0); target->tdir.SetXYZ(0.0, 1.0, 0.0); target->udir.SetXYZ(0.0, 0.0, 1.0); target->L = 30.0; MAX_HIT_DIST = 2.0; // cm DEBUG_HISTS = false; USE_CDC = true; USE_FDC_ANODE = true; USE_FDC_CATHODE = true; MAX_CHISQ_DIFF = 1.0E-2; MAX_FIT_ITERATIONS = 50; SIGMA_CDC = 0.0150; SIGMA_FDC_ANODE = 0.0200; SIGMA_FDC_CATHODE = 0.0200; CHISQ_MAX_RESI_SIGMAS = 100.0; CHISQ_GOOD_LIMIT = 2.0; LEAST_SQUARES_DP = 0.0001; LEAST_SQUARES_DX = 0.010; LEAST_SQUARES_MIN_HITS = 3; LEAST_SQUARES_MAX_E2NORM = 1.0E8; DEFAULT_STEP_SIZE = 0.5; MIN_CDC_HIT_PROB = 0.2; MAX_CDC_DOUBLE_HIT_PROB = 0.1; MIN_FDC_HIT_PROB = 0.2; MAX_FDC_DOUBLE_HIT_PROB = 0.1; TOF_MASS = 0.13957018; gPARMS->SetDefaultParameter("TRKFIT:MAX_HIT_DIST", MAX_HIT_DIST); gPARMS->SetDefaultParameter("TRKFIT:DEBUG_HISTS", DEBUG_HISTS); gPARMS->SetDefaultParameter("TRKFIT:USE_CDC", USE_CDC); gPARMS->SetDefaultParameter("TRKFIT:USE_FDC_ANODE", USE_FDC_ANODE); gPARMS->SetDefaultParameter("TRKFIT:USE_FDC_CATHODE", USE_FDC_CATHODE); gPARMS->SetDefaultParameter("TRKFIT:MAX_CHISQ_DIFF", MAX_CHISQ_DIFF); gPARMS->SetDefaultParameter("TRKFIT:MAX_FIT_ITERATIONS", MAX_FIT_ITERATIONS); gPARMS->SetDefaultParameter("TRKFIT:SIGMA_CDC", SIGMA_CDC); gPARMS->SetDefaultParameter("TRKFIT:SIGMA_FDC_ANODE", SIGMA_FDC_ANODE); gPARMS->SetDefaultParameter("TRKFIT:SIGMA_FDC_CATHODE", SIGMA_FDC_CATHODE); gPARMS->SetDefaultParameter("TRKFIT:CHISQ_MAX_RESI_SIGMAS", CHISQ_MAX_RESI_SIGMAS); gPARMS->SetDefaultParameter("TRKFIT:CHISQ_GOOD_LIMIT", CHISQ_GOOD_LIMIT); gPARMS->SetDefaultParameter("TRKFIT:LEAST_SQUARES_DP", LEAST_SQUARES_DP); gPARMS->SetDefaultParameter("TRKFIT:LEAST_SQUARES_DX", LEAST_SQUARES_DX); gPARMS->SetDefaultParameter("TRKFIT:LEAST_SQUARES_MIN_HITS",LEAST_SQUARES_MIN_HITS); gPARMS->SetDefaultParameter("TRKFIT:LEAST_SQUARES_MAX_E2NORM",LEAST_SQUARES_MAX_E2NORM); gPARMS->SetDefaultParameter("TRKFIT:DEFAULT_STEP_SIZE", DEFAULT_STEP_SIZE); gPARMS->SetDefaultParameter("TRKFIT:MIN_CDC_HIT_PROB", MIN_CDC_HIT_PROB); gPARMS->SetDefaultParameter("TRKFIT:MAX_CDC_DOUBLE_HIT_PROB", MAX_CDC_DOUBLE_HIT_PROB); gPARMS->SetDefaultParameter("TRKFIT:MIN_FDC_HIT_PROB", MIN_FDC_HIT_PROB); gPARMS->SetDefaultParameter("TRKFIT:MAX_FDC_DOUBLE_HIT_PROB", MAX_FDC_DOUBLE_HIT_PROB); gPARMS->SetDefaultParameter("TRKFIT:TOF_MASS", TOF_MASS); } //------------------ // DTrack_factory_ALT2 (Destructor) //------------------ DTrack_factory_ALT2::~DTrack_factory_ALT2() { if(tmprt)delete tmprt; for(unsigned int i=0; iSetParameter("GEOM:BZ_CONST", -2.0); DApplication* dapp = dynamic_cast(eventLoop->GetJApplication()); bfield = dapp->GetBfield(); // temporary until new geometry scheme is worked out // (re)-allocate temporary DReferenceTrajectory used in // numerical derivatives if(tmprt)delete tmprt; tmprt = new DReferenceTrajectory(bfield); // Set limits on CDC. (This should eventually come from HDDS) CDC_Z_MIN = 17.0; CDC_Z_MAX = CDC_Z_MIN + 175.0; hit_based = false; //cout<<__FILE__<<":"<<__LINE__<<"-------------- Helical Fitter TRACKING --------------"<Lock(); // Histograms may already exist. (Another thread may have created them) // Try and get pointers to the existing ones. cdcdoca_vs_dist = (TH2F*)gROOT->FindObject("cdcdoca_vs_dist"); cdcdoca_vs_dist_vs_ring = (TH3F*)gROOT->FindObject("cdcdoca_vs_dist_vs_ring"); fdcdoca_vs_dist = (TH2F*)gROOT->FindObject("fdcdoca_vs_dist"); fdcu_vs_s = (TH2F*)gROOT->FindObject("fdcu_vs_s"); dist_axial = (TH1F*)gROOT->FindObject("dist_axial"); doca_axial = (TH1F*)gROOT->FindObject("doca_axial"); dist_stereo = (TH1F*)gROOT->FindObject("dist_stereo"); doca_stereo = (TH1F*)gROOT->FindObject("doca_stereo"); chisq_final_vs_initial = (TH2F*)gROOT->FindObject("chisq_final_vs_initial"); nhits_final_vs_initial = (TH2F*)gROOT->FindObject("nhits_final_vs_initial"); Npasses = (TH1F*)gROOT->FindObject("Npasses"); ptotal = (TH1F*)gROOT->FindObject("ptotal"); residuals_cdc = (TH2F*)gROOT->FindObject("residuals_cdc"); residuals_fdc_anode = (TH2F*)gROOT->FindObject("residuals_fdc_anode"); residuals_fdc_cathode = (TH2F*)gROOT->FindObject("residuals_fdc_cathode"); residuals_cdc_vs_s = (TH3F*)gROOT->FindObject("residuals_cdc_vs_s"); residuals_fdc_anode_vs_s = (TH3F*)gROOT->FindObject("residuals_fdc_anode_vs_s"); residuals_fdc_cathode_vs_s = (TH3F*)gROOT->FindObject("residuals_fdc_cathode_vs_s"); initial_chisq_vs_Npasses = (TH2F*)gROOT->FindObject("initial_chisq_vs_Npasses"); chisq_vs_pass = (TH2F*)gROOT->FindObject("chisq_vs_pass"); dchisq_vs_pass = (TH2F*)gROOT->FindObject("dchisq_vs_pass"); cdc_single_hit_prob = (TH1F*)gROOT->FindObject("cdc_single_hit_prob"); cdc_double_hit_prob = (TH1F*)gROOT->FindObject("cdc_double_hit_prob"); fdc_single_hit_prob = (TH1F*)gROOT->FindObject("fdc_single_hit_prob"); fdc_double_hit_prob = (TH1F*)gROOT->FindObject("fdc_double_hit_prob"); cdc_can_resi = (TH1F*)gROOT->FindObject("cdc_can_resi"); fdc_can_resi = (TH1F*)gROOT->FindObject("fdc_can_resi"); fdc_can_resi_cath = (TH1F*)gROOT->FindObject("fdc_can_resi_cath"); if(!cdcdoca_vs_dist)cdcdoca_vs_dist = new TH2F("cdcdoca_vs_dist","DOCA vs. DIST",300, 0.0, 1.2, 300, 0.0, 1.2); if(!cdcdoca_vs_dist_vs_ring)cdcdoca_vs_dist_vs_ring = new TH3F("cdcdoca_vs_dist_vs_ring","DOCA vs. DIST vs. ring",300, 0.0, 1.2, 300, 0.0, 1.2,23,0.5,23.5); if(!fdcdoca_vs_dist)fdcdoca_vs_dist = new TH2F("fdcdoca_vs_dist","DOCA vs. DIST",500, 0.0, 2.0, 500, 0.0, 2.0); if(!fdcu_vs_s)fdcu_vs_s = new TH2F("fdcu_vs_s","DOCA vs. DIST along wire",500, -60.0, 60.0, 500, -60.0, 60.0); if(!dist_axial)dist_axial = new TH1F("dist_axial","Distance from drift time for axial CDC wires",300,0.0,3.0); if(!doca_axial)doca_axial = new TH1F("doca_axial","DOCA of track for axial CDC wires",300,0.0,3.0); if(!dist_stereo)dist_stereo = new TH1F("dist_stereo","Distance from drift time for stereo CDC wires",300,0.0,3.0); if(!doca_stereo)doca_stereo = new TH1F("doca_stereo","DOCA of track for axial CDC wires",300,0.0,3.0); if(!chisq_final_vs_initial)chisq_final_vs_initial = new TH2F("chisq_final_vs_initial","Final vs. initial chi-sq.",200, 0.0, 10.0,50, 0.0, 2.5); if(!nhits_final_vs_initial)nhits_final_vs_initial = new TH2F("nhits_final_vs_initial","Final vs. initial nhits used in chi-sq.",30, -0.5, 29.5, 30, -0.5, 29.5); if(!Npasses)Npasses = new TH1F("Npasses","Npasses", 101, -0.5, 100.5); if(!ptotal)ptotal = new TH1F("ptotal","ptotal",1000, 0.1, 8.0); if(!residuals_cdc)residuals_cdc = new TH2F("residuals_cdc","Residuals in CDC",1000,-2.0,2.0,24,0.5,24.5); if(!residuals_fdc_anode)residuals_fdc_anode = new TH2F("residuals_fdc_anode","Residuals in FDC anodes",1000,-2.0,2.0,24,0.5,24.5); if(!residuals_fdc_cathode)residuals_fdc_cathode = new TH2F("residuals_fdc_cathode","Residuals in FDC cathode",1000,-2.0,2.0,24,0.5,24.5); if(!residuals_cdc_vs_s)residuals_cdc_vs_s = new TH3F("residuals_cdc_vs_s","Residuals in CDC vs. pathlength",1000,-2.0,2.0,24,0.5,24.5,100, 0.0, 800); if(!residuals_fdc_anode_vs_s)residuals_fdc_anode_vs_s = new TH3F("residuals_fdc_anode_vs_s","Residuals in FDC anode vs. pathlength",1000,-2.0,2.0,24,0.5,24.5,100, 0.0, 800); if(!residuals_fdc_cathode_vs_s)residuals_fdc_cathode_vs_s = new TH3F("residuals_fdc_cathode_vs_s","Residuals in FDC cathode vs. pathlength",1000,-2.0,2.0,24,0.5,24.5,100, 0.0, 800); if(!initial_chisq_vs_Npasses)initial_chisq_vs_Npasses = new TH2F("initial_chisq_vs_Npasses","Initial chi-sq vs. number of iterations", 25, -0.5, 24.5, 400, 0.0, 40.0); if(!chisq_vs_pass)chisq_vs_pass = new TH2F("chisq_vs_pass","Chi-sq vs. fit iteration", 25, -0.5, 24.5, 400, 0.0, 40.0); if(!dchisq_vs_pass)dchisq_vs_pass = new TH2F("dchisq_vs_pass","Change in Chi-sq vs. fit iteration", 25, -0.5, 24.5, 400, 0.0, 8.0); if(!cdc_single_hit_prob)cdc_single_hit_prob = new TH1F("cdc_single_hit_prob","Probability a CDC hit belongs to a track for all tracks",200,0.0,1.0); if(!cdc_double_hit_prob)cdc_double_hit_prob = new TH1F("cdc_double_hit_prob","Probability a CDC hit belongs to two tracks",200,0.0,1.0); if(!fdc_single_hit_prob)fdc_single_hit_prob = new TH1F("fdc_single_hit_prob","Probability a FDC hit belongs to a track for all tracks",200,0.0,1.0); if(!fdc_double_hit_prob)fdc_double_hit_prob = new TH1F("fdc_double_hit_prob","Probability a FDC hit belongs to two tracks",200,0.0,1.0); if(!cdc_can_resi)cdc_can_resi = new TH1F("cdc_can_resi","Residual of CDC hits with candidate tracks", 200, -1.0, 1.0); if(!fdc_can_resi)fdc_can_resi = new TH1F("fdc_can_resi","Residual of FDC hits with candidate tracks", 200, -1.0, 1.0); if(!fdc_can_resi_cath)fdc_can_resi_cath = new TH1F("fdc_can_resi_cath","Residual of FDC cathode hits with candidate tracks", 200, -1.0, 1.0); dapp->Unlock(); } return NOERROR; } //------------------ // evnt //------------------ jerror_t DTrack_factory_ALT2::evnt(JEventLoop *loop, int eventnumber) { // Store current event number this->eventnumber = eventnumber; // Get input data trackcandidates.clear(); cdctrackhits.clear(); fdctrackhits.clear(); loop->Get(trackcandidates); loop->Get(cdctrackhits); loop->Get(fdctrackhits); // Calculate the probablity of each hit belonging to each candidate FindHitCandidateProbabilities(); // Consistency check if(cdctrackhits.size()!=cdcprobs.size() || fdctrackhits.size()!=fdcprobs.size()){ _DBG_<<"Hit vector and assignment vector not the same size!"<1){ _DBG__; _DBG_<<"============ Fitting Candidate "<=MIN_CDC_HIT_PROB)cdchits_on_track.push_back(cdctrackhits[j]); } fdchits_on_track.clear(); for(unsigned int j=0; j=MIN_FDC_HIT_PROB)fdchits_on_track.push_back(fdctrackhits[j]); } // Fit the track DTrack *track = FitTrack(rtv[i], trackcandidates[i]->id); // Try fitting with the opposite charge if(track==NULL || (track!=NULL && track->chisq>2.0)){ track = FitTrackWithOppositeCharge(rtv[i], trackcandidates[i]->id, track); } // If fit is successful, then store the track if(track)_data.push_back(track); } return NOERROR; } //------------------ // fini //------------------ jerror_t DTrack_factory_ALT2::fini(void) { return NOERROR; } //------------------ // FitTrack //------------------ DTrack* DTrack_factory_ALT2::FitTrack(DReferenceTrajectory* rt, int candidateid) { /// Fit a track candidate // Debug message if(debug_level>2){ _DBG__; _DBG_<<"cdchits_on_track.size="<2)_DBG_<<"Hit based fit succeeded for candidate "<2)_DBG_<<"Hit based fit showed no improvement for candidate "<2)_DBG_<<"Maybe time based will improve things ... "<2)_DBG_<<"Hit based fit failed for candidate "<3)_DBG_<<"============= Time-based ==============="<2)_DBG_<<"Time based fit succeeded for candidate "<2)_DBG_<<"Time based fit unable to improve candidate "<2)_DBG_<<"Time based fit failed for candidate "<Fill(Niterations+1, chisq_time_based); dchisq_vs_pass->Fill(Niterations+1, last_chisq-chisq_time_based); } // If the chisq is too large, then consider it a hopeless cause if(chisq_time_based>1.0E4){ if(debug_level>3)_DBG_<<"Time based fit chisq too large for candidate "<1)_DBG_<<" Niterations="<q>0 ? "+":"-")<<" now:"<<(rt->q>0 ? "-":"+")<<")"<swim_steps[0]; DVector3 pos = start_step.origin; DVector3 mom = start_step.mom; rt->Swim(pos, mom, -rt->q); if(rt->Nswim_steps==0)return track; // Try fitting track DTrack *track_bar = FitTrack(rt, candidateid); // Decide which (if any) track to keep if((track==NULL) && (track_bar==NULL)){ if(debug_level>3)_DBG_<<"Track fits failed both q and q_bar"<3)_DBG_<<"Track fit failed q but succeeded for q_bar"<3)_DBG_<<"Track fit failed q_bar but succeeded for q"<chisq < track->chisq){ if(debug_level>3)_DBG_<<"Keeping opposite charged track"<3)_DBG_<<"Keeping original charge track"<Swim(pos, mom, -rt->q); // re-swim with original charge } return track; } //------------------ // FindHitCandidateProbabilities //------------------ void DTrack_factory_ALT2::FindHitCandidateProbabilities(void) { /// Sort all CDC and FDC hits by which track candidate they most likely belong to. /// /// For each hit this calculates the probabilities that it came /// from each of the track candidates. Hits are then assigned /// to a candidate according to highest probability. Hits /// are also dropped if the probability of belonging to /// more than one track is sufficiently large. // Allocate more DReferenceTrajectory objects if needed. // These each have a large enough memory footprint that // it causes noticable performance problems if we allocated // and deallocated them every event. Therefore, we allocate // when needed, but recycle them on the next event. // They are delete in the factory deconstructor. while(rtv.size()position(); const DVector3 &mom = tc->momentum(); rt->Swim(pos, mom, tc->charge()); if(rt->Nswim_steps<1){ for(unsigned int j=0; j cdcprob; GetCDCTrackHitProbabilities(rt, cdcprob); for(unsigned int j=0; j fdcprob; GetFDCTrackHitProbabilities(rt, fdcprob); for(unsigned int j=0; j10){ _DBG_<<"Candidate "<s<<" resi="<sdir.Cross(start_step->mom); vdir.SetMag(1.0); // Momentum in RT coordinate system DVector3 mom_rt; double p = 1.0/state[state_curvature][0]; double theta = state[state_dip][0]-M_PI; double phi = state[state_phi][0]; if(theta<0.0){ theta = -theta; phi += M_PI; } mom_rt.SetMagThetaPhi(p, theta, phi); DVector3 pos = start_step->origin + state[state_x ][0]*start_step->sdir + state[state_v ][0]*vdir; DVector3 mom = mom_rt.X()*start_step->sdir + mom_rt.Y()*start_step->tdir + mom_rt.Z()*start_step->udir; if(!rt){ _DBG_<<"NULL pointer passed for DReferenceTrajectory object!"<200.0 || fabs(state[state_x ][0])>100.0 || fabs(state[state_v ][0])>100.0){ if(debug_level>3)_DBG_<<"state values out of range"<6){ pos.Print(); mom.Print(); _DBG_<<"state[state_x ][0]="<swim_steps[0]; DVector3 pos = start_step.origin; DVector3 mom = start_step.mom; // Make list of wires vector wires; vector shifts; vector errs; #if 1 // --- Target --- // Define the target as though it were a wire so it is included // in the chi-sq DCoordinateSystem target; target.origin.SetXYZ(0.0, 0.0, pos.Z()); target.sdir.SetXYZ(1.0, 0.0, 0.0); target.tdir.SetXYZ(0.0, 1.0, 0.0); target.udir.SetXYZ(0.0, 0.0, 1.0); target.L=3.0; wires.push_back(&target); errs.push_back(fit_type==kHitBased ? 0.001:0.02); if(fit_type!=kHitBased)shifts.push_back(DVector3(0.0, 0.0, 0.0)); #endif // --- CDC --- for(unsigned int i=0; iwire; wires.push_back(wire); // Fill in shifts and errs vectors based on whether we're doing // hit-based or time-based tracking if(fit_type==kHitBased){ // If we're doing hit-based tracking then only the wire positions // are used and the drift time info is ignored. Thus, we don't // have to calculate the shift vectors errs.push_back(0.261694); // empirically from single pi+ events }else{ // Find the DOCA point for the RT and use the momentum direction // there and the wire direction to determine the "shift". // Note that whether the shift is to the left or to the right // is not decided here. That ambiguity is left to be resolved later // by applying a minus sign (or not) to the shift. DVector3 pos_doca, mom_doca; double s; rt->DistToRT(wire, &s); rt->GetLastDOCAPoint(pos_doca, mom_doca); DVector3 shift = wire->udir.Cross(mom_doca); // The magnitude of the shift is based on the drift time. The // value of the dist member of the DCDCTrackHit object does not // subtract out the TOF. This can add 50-100 microns to the // resolution in the CDC. Here, we actually can calculate the TOF // (for a given mass hypothesis). double mass = 0.13957; double beta = 1.0/sqrt(1.0 + pow(mass/mom_doca.Mag(), 2.0))*2.998E10; double tof = s/beta/1.0E-9; // in ns double dist = hit->dist*((hit->tdrift-tof)/hit->tdrift); shift.SetMag(dist); // If we're doing time-based tracking then there is a sign ambiguity // to each of the "shifts". It is not realistic to check every possible // solution so we have to make a guess as to what the sign is for each // based on the current reference trajectory. Presumably, if, we're // doing time-based track fitting then we have already gone through a pass // of hit-based track fitting so the initial reference trajectory should be // a pretty good indicator as to what side of the wire the track went // on. We use this in the assignments for now. In the future, we should // try multiple cases for hits close to the wire where the ambiguity // is not clearly resolved. // shift needs to be in the direction pointing from the avalanche // position on the wire to the DOCA point on the rt. We find this // by first finding this vector for the rt and then seeing if // the "shift" vector is generally pointing in the same direction // as it or not by checking if thier dot product is positive or // negative. double u = rt->GetLastDistAlongWire(); DVector3 pos_wire = wire->origin + u*wire->udir; DVector3 pos_diff = pos_doca-pos_wire; if(shift.Dot(pos_diff)<0.0)shift = -shift; shifts.push_back(shift); errs.push_back(SIGMA_CDC); } } // --- FDC --- for(unsigned int i=0; iwire; wires.push_back(wire); // Fill in shifts and errs vectors based on whether we're doing // hit-based or time-based tracking if(fit_type==kHitBased){ // If we're doing hit-based tracking then only the wire positions // are used and the drift time info is ignored. Thus, we don't // have to calculate the shift vectors errs.push_back(0.261694); // empirically from single pi+ events }else{ // Find the DOCA point for the RT and use the momentum direction // there and the wire direction to determine the "shift". // Note that whether the shift is to the left or to the right // is not decided here. That ambiguity is left to be resolved later // by applying a minus sign (or not) to the shift. DVector3 pos_doca, mom_doca; double s; rt->DistToRT(wire, &s); rt->GetLastDOCAPoint(pos_doca, mom_doca); DVector3 shift = wire->udir.Cross(mom_doca); // The magnitude of the shift is based on the drift time. The // value of the dist member of the DCDCTrackHit object does not // subtract out the TOF. This can add 50-100 microns to the // resolution in the CDC. Here, we actually can calculate the TOF // (for a given mass hypothesis). double mass = 0.13957; double beta = 1.0/sqrt(1.0 + pow(mass/mom_doca.Mag(), 2.0))*2.998E10; double tof = s/beta/1.0E-9; // in ns double dist = hit->dist*((hit->time-tof)/hit->time); shift.SetMag(dist); // If we're doing time-based tracking then there is a sign ambiguity // to each of the "shifts". It is not realistic to check every possible // solution so we have to make a guess as to what the sign is for each // based on the current reference trajectory. Presumably, if, we're // doing time-based track fitting then we have already gone through a pass // of hit-based track fitting so the initial reference trajectory should be // a pretty good indicator as to what side of the wire the track went // on. We use this in the assignments for now. In the future, we should // try multiple cases for hits close to the wire where the ambiguity // is not clearly resolved. // shift needs to be in the direction pointing from the avalanche // position on the wire to the DOCA point on the rt. We find this // by first finding this vector for the rt and then seeing if // the "shift" vector is generally pointing in the same direction // as it or not by checking if thier dot product is positive or // negative. double u = rt->GetLastDistAlongWire(); DVector3 pos_wire = wire->origin + u*wire->udir; DVector3 pos_diff = pos_doca-pos_wire; if(shift.Dot(pos_diff)<0.0)shift = -shift; shifts.push_back(shift); errs.push_back(SIGMA_FDC_ANODE); } } // Get the chi-squared vector for the initial reference trajectory vector chisqv_initial; double initial_chisq = ChiSq(rt, wires, shifts, errs, chisqv_initial); // Derive state parameters from momentum vector double px_rt = mom.Dot(start_step.sdir); double py_rt = mom.Dot(start_step.tdir); double pz_rt = mom.Dot(start_step.udir); DVector3 mom_rt(px_rt, py_rt, pz_rt); double p_rt = mom_rt.Mag(); double dip_rt = mom_rt.Theta()+M_PI; double phi_rt = mom_rt.Phi(); // Because we have a non-linear system, we must take the derivatives // numerically. // // Note that in the calculations of the deltas below, // the change in state should be set first and the value // of deltas[...] calculated from that. See Numerical // Recipes in C 2nd ed. section 5.7 ppg. 186-189. const int Nparameters = 5; double deltas[Nparameters]; DMatrix state(5,1); switch(Nparameters){ case 5: state[state_v ][0] = 0.0; case 4: state[state_x ][0] = 0.0; case 3: state[state_phi ][0] = phi_rt; case 2: state[state_dip ][0] = dip_rt; case 1: state[state_curvature ][0] = 1.0/p_rt; } // For the swimming below, we use a second reference trajectory so as // to preserve the original. Set the charge here. The rest of the // parameters (starting position and momentum) will be set using // values from the state vector. tmprt->q = rt->q; // dpx : tweak by +/- 0.01 DMatrix state_dcurvature = state; state_dcurvature[state_curvature][0] += 1.0E-3; deltas[state_curvature] = state_dcurvature[state_curvature][0] - state[state_curvature][0]; vector &chisqv_dcurvature_lo = chisqv_initial; vector chisqv_dcurvature_hi; double chisq_dcurvature = ChiSq(state_dcurvature, &start_step, tmprt, wires, shifts, errs, chisqv_dcurvature_hi); // dpy : tweak by +/- 0.01 DMatrix state_ddip = state; state_ddip[state_dip][0] += 1.0E-2; deltas[state_dip] = state_ddip[state_dip][0] - state[state_dip][0]; vector &chisqv_ddip_lo = chisqv_initial; vector chisqv_ddip_hi; double chisq_ddip = ChiSq(state_ddip, &start_step, tmprt, wires, shifts, errs, chisqv_ddip_hi); // dpz : tweak by +/- 0.01 DMatrix state_dphi = state; state_dphi[state_phi][0] += 1.0E-3; deltas[state_phi] = state_dphi[state_phi][0] - state[state_phi][0]; vector &chisqv_dphi_lo = chisqv_initial; vector chisqv_dphi_hi; double chisq_dphi = ChiSq(state_dphi, &start_step, tmprt, wires, shifts, errs, chisqv_dphi_hi); // dv : tweak by +/- 0.01 DMatrix state_dv = state; state_dv[state_v][0] += LEAST_SQUARES_DX; deltas[state_v] = state_dv[state_v][0] - state[state_v][0]; vector &chisqv_dv_lo = chisqv_initial; vector chisqv_dv_hi; double chisq_dv = ChiSq(state_dv, &start_step, tmprt, wires, shifts, errs, chisqv_dv_hi); // dx : tweak by +/- 0.01 DMatrix state_dx = state; state_dx[state_x][0] += LEAST_SQUARES_DX; deltas[state_x] = state_dx[state_x][0] - state[state_x][0]; vector &chisqv_dx_lo = chisqv_initial; vector chisqv_dx_hi; double chisq_dx = ChiSq(state_dx, &start_step, tmprt, wires, shifts, errs, chisqv_dx_hi); // This line just avoids a compiler warning if(debug_level>4){ _DBG_<<"initial_chisq="< good; unsigned int Ngood=0; unsigned int Nhits = wires.size(); for(unsigned int i=0; i1.0 ? initial_chisq:1.0); double sigma; //_DBG_<<"sigma="<max){good.push_back(false); continue;} sigma = chisqv_dcurvature_hi[i]; if(!finite(sigma) || fabs(sigma)>max){good.push_back(false); continue;} sigma = chisqv_ddip_hi[i]; if(!finite(sigma) || fabs(sigma)>max){good.push_back(false); continue;} sigma = chisqv_dphi_hi[i]; if(!finite(sigma) || fabs(sigma)>max){good.push_back(false); continue;} sigma = chisqv_dx_hi[i]; if(!finite(sigma) || fabs(sigma)>max){good.push_back(false); continue;} sigma = chisqv_dv_hi[i]; if(!finite(sigma) || fabs(sigma)>max){good.push_back(false); continue;} good.push_back(true); Ngood++; } if(Ngood2)_DBG_<<" Bad number of good distance calculations!(Ngood="<1)_DBG_<<" -- B matrix invalid"< LEAST_SQUARES_MAX_E2NORM){ if(debug_level>1){ _DBG_<<" -- B matrix E2Norm out of range(E2Norm="< new_chisqv; chisq = ChiSq(new_state, &start_step, tmprt, wires, shifts, errs, new_chisqv); if(chisq4)_DBG_<<" -- initial_chisq="< new_chisqv; chisq = ChiSq(new_state, &start_step, rt, wires, shifts, errs, new_chisqv); if(debug_level>3){ DVector3 pos = start_step.origin; DVector3 mom = start_step.mom; double phi = mom.Phi(); if(phi<0.0)phi+=2.0*M_PI; _DBG_<<"LeastSquaresB succeeded: p="<Swim(pos,mom); own_rt = true; } double chisq = ChiSq(q, rt); // If we created the reference trajectory, then delete if(own_rt)delete rt; return chisq; } //------------------ // ChiSq //------------------ double DTrack_factory_ALT2::ChiSq(double q, DReferenceTrajectory *rt) { // Clear chisq and sigma vector chisqv.clear(); sigmav.clear(); if(rt->Nswim_steps<3)return 1.0E6; // Calculate particle beta double beta = 1.0/sqrt(1.0+TOF_MASS*TOF_MASS/rt->swim_steps[0].mom.Mag2()); // assume this is a pion for now. This should eventually come from outer detectors // Add CDC hits (if any) for(unsigned int i=0; iwire; // Distance of closest approach for track to wire double s; double doca = rt->DistToRT(wire, &s); // Distance from drift time. Hardwired for simulation for now double dist, sigma; if(hit_based){ dist=0.400; // Middle of the tube is best guess when no time info is present sigma = 2.0*dist/3.464; // sigma of flat distr. is W/sqrt(12) where W is total width }else{ // Calculate time of flight (TOF) so we can subtract it double tof = s/(beta*3E10*1E-9); dist = (hit->tdrift-tof)*55E-4; sigma = SIGMA_CDC; // 200 um //sigma += 0.010*s/100.0; // add 50 um per meter due to MULS } // NOTE: Sometimes we push nan or large values on here double resi = dist - doca; chisqv.push_back(USE_CDC ? resi:NaN); sigmav.push_back(sigma); } // Add FDC hits (if any) for(unsigned int i=0; iwire; // Distance of closest approach for track to wire double s; double doca = rt->DistToRT(wire,&s); // Distance from drift time. Hardwired for simulation for now. double dist, sigma; if(hit_based){ dist = 1.116/4.0; // 1/4 of wire spacing is best guess when no time info is present sigma = 2.0*dist/3.464; // sigma of flat distr. is W/sqrt(12) where W is total width }else{ // Calculate time of flight (TOF) so we can subtract it double tof = s/(beta*3E10*1E-9); dist = (hit->time-tof)*55E-4; sigma = SIGMA_FDC_ANODE; // 200 um //sigma += 0.010*s/100.0; // add 50 um per meter due to MULS } // NOTE: Sometimes we push nan or large values on here double resi = dist - doca; chisqv.push_back(USE_FDC_ANODE ? resi:NaN); sigmav.push_back(sigma); // For the FDC we also have a measurement along the wire // which we include as a separate measurement double u = rt->GetLastDistAlongWire(); resi = u - hit->s; sigma = SIGMA_FDC_CATHODE; //sigma += 0.010*s/100.0; // add 50 um per meter due to MULS chisqv.push_back(USE_FDC_CATHODE ? resi:NaN); sigmav.push_back(sigma); // 200 um } // Include distance from target as element of chi-sq. This will // need to be changed for off-beamline vertices. double s; double d = rt->DistToRT(target, &s); chisqv.push_back(d); sigmav.push_back(0.1); // 1 mm // Filter out all but the best hits from the chisq // If we have at least 10 hits, then throw away the // worst 10% of the hits. vector tmp; for(unsigned int i=0; i10)index = (unsigned int)((float)index*0.9); double chisq_max_resi_sigmas = tmp[index]; // Add "good" hits together to get the chi-squared double chisq = 0; Ngood_chisq_hits=0.0; for(unsigned int i=0; iCHISQ_MAX_RESI_SIGMAS)continue; //if(fabs(chisqv[i]/sigmav[i])>chisq_max_resi_sigmas)continue; chisq+=pow(chisqv[i]/sigmav[i], 2.0); Ngood_chisq_hits += 1.0; } chisq/=Ngood_chisq_hits; if(debug_level>10)_DBG_<<"Chisq: Ngood_chisq_hits="<swim_steps[0]; DVector3 vdir = start_step.sdir.Cross(start_step.mom); vdir.SetMag(1.0); // Since we define the state in the X/V plane, we need to propagate the // particle from the given starting position up to this plane. DVector3 pos = start_pos; DVector3 mom = start_mom; // DMagneticFieldStepper stepper(bfield, rt->q); // if(stepper.SwimToPlane(pos, mom, start_step.origin, start_step.udir)){ //return FIT_FAILED; // } // Define the particle state in the reference trajectory coordinate // system at the start of the RT DVector3 pos_diff = pos - start_step.origin; DMatrix state(5,1); switch(Nparameters){ case 5: state[state_v ][0] = pos_diff.Dot(vdir); case 4: state[state_x ][0] = pos_diff.Dot(start_step.sdir); case 3: state[state_phi ][0] = mom.Dot(start_step.udir); case 2: state[state_dip ][0] = mom.Dot(start_step.tdir); case 1: state[state_curvature ][0] = mom.Dot(start_step.sdir); } // Create reference trajectory to use in calculating derivatives tmprt->Swim(pos,mom, rt->q); // Best-guess chisq = ChiSq(rt->q, tmprt); vector resi = chisqv; vector errs = sigmav; // Because we have a non-linear system, we must take the derivatives // numerically. // // Note that in the calculations of the deltas below, // the change in state should be set first and the value // of deltas[...] calculated from that. See Numerical // Recipes in C 2nd ed. section 5.7 ppg. 186-189. // dpx : tweak by +/- 0.01 DMatrix state_dcurvature = state; state_dcurvature[state_curvature][0] += LEAST_SQUARES_DP; deltas[state_curvature] = state_dcurvature[state_curvature][0] - state[state_curvature][0]; ChiSq(rt->q, state_dcurvature, &start_step,tmprt); vector resi_dpx_hi = chisqv; vector &resi_dpx_lo = resi; // dpy : tweak by +/- 0.01 DMatrix state_ddip = state; state_ddip[state_dip][0] += LEAST_SQUARES_DP; deltas[state_dip] = state_ddip[state_dip][0] - state[state_dip][0]; ChiSq(rt->q, state_ddip, &start_step,tmprt); vector resi_dpy_hi = chisqv; vector &resi_dpy_lo = resi; // dpz : tweak by +/- 0.01 DMatrix state_dphi = state; state_dphi[state_phi][0] += LEAST_SQUARES_DP; deltas[state_phi] = state_dphi[state_phi][0] - state[state_phi][0]; ChiSq(rt->q, state_dphi, &start_step,tmprt); vector resi_dpz_hi = chisqv; vector &resi_dpz_lo = resi; // dx : tweak by +/- 0.01 DMatrix state_dx = state; state_dx[state_x][0] += LEAST_SQUARES_DX; deltas[state_x] = state_dx[state_x][0] - state[state_x][0]; if(Nparameters>=4)ChiSq(rt->q, state_dx, &start_step,tmprt); vector resi_dx_hi = chisqv; vector &resi_dx_lo = resi; // dv : tweak by +/- 0.01 DMatrix state_dv = state; state_dv[state_v][0] += LEAST_SQUARES_DX; deltas[state_v] = state_dv[state_v][0] - state[state_v][0]; if(Nparameters>=5)ChiSq(rt->q, state_dv, &start_step,tmprt); vector resi_dv_hi = chisqv; vector &resi_dv_lo = resi; // Make a list of "clean" hits. Ones with reasonably // small, residuals that are not "nan" for the // best-guess as well as the tweaked cases. vector good; unsigned int Ngood=0; unsigned int Nhits = resi.size(); for(unsigned int i=0; imax){good.push_back(false); continue;} res = resi_dpx_hi[i]; if(!finite(res) || fabs(res)>max){good.push_back(false); continue;} res = resi_dpy_hi[i]; if(!finite(res) || fabs(res)>max){good.push_back(false); continue;} res = resi_dpz_hi[i]; if(!finite(res) || fabs(res)>max){good.push_back(false); continue;} res = resi_dx_hi[i]; if(!finite(res) || fabs(res)>max){good.push_back(false); continue;} res = resi_dv_hi[i]; if(!finite(res) || fabs(res)>max){good.push_back(false); continue;} good.push_back(true); Ngood++; } if(Ngood2)_DBG_<<" Bad number of good distance calculations!"<1)_DBG_<<" -- B matrix invalid"< LEAST_SQUARES_MAX_E2NORM){ if(debug_level>1)_DBG_<<" -- B matrix E2Norm out of range(E2Norm="<Swim(vertex_pos, vertex_mom); new_chisq = ChiSq(rt->q, rt); // If we're at a lower chi-sq then we're done if(debug_level>4)_DBG_<<" -- chisq="<Swim(vertex_pos, vertex_mom); ptotal->Fill(vertex_mom.Mag()); // Calculate particle beta double beta = 1.0/sqrt(1.0+TOF_MASS*TOF_MASS/vertex_mom.Mag2()); // assume this is a pion for now. This should eventually come from outer detectors for(unsigned int j=0; jwire; // Distance of closest approach for track to wire double s; double doca = rt->DistToRT(wire, &s); // Distance from drift time. Hardwired for simulation for now double tof = s/(beta*3E10*1E-9); double dist = (hit->tdrift-tof)*55E-4; // NOTE: Sometimes this could be nan double resi = dist - doca; if(!finite(resi))continue; // Fill histos residuals_cdc->Fill(resi, wire->ring); residuals_cdc_vs_s->Fill(resi, wire->ring, s); cdcdoca_vs_dist->Fill(dist, doca); cdcdoca_vs_dist_vs_ring->Fill(dist, doca, wire->ring); if(wire->stereo==0.0){ dist_axial->Fill(dist); doca_axial->Fill(doca); }else{ dist_stereo->Fill(dist); doca_stereo->Fill(doca); } } for(unsigned int j=0; jwire; // Distance of closest approach for track to wire double s; double doca = rt->DistToRT(wire,&s); double tof = s/(beta*3E10*1E-9); double dist = (hit->time-tof)*55E-4; // NOTE: Sometimes this is nan double resi = dist - doca; if(finite(resi)){ fdcdoca_vs_dist->Fill(dist, doca); residuals_fdc_anode->Fill(resi, wire->layer); residuals_fdc_anode_vs_s->Fill(resi, wire->layer,s); } double u = rt->GetLastDistAlongWire(); resi = u - hit->s; if(finite(resi)){ fdcu_vs_s->Fill(u, hit->s); residuals_fdc_cathode->Fill(resi, wire->layer); residuals_fdc_cathode_vs_s->Fill(resi, wire->layer,s); } } // Find chi-sq for both initial and final values #if 0 double chisq_final = ChiSq(rt->q, rt); double nhits_final = Ngood_chisq_hits; DVector3 mom; mom.SetMagThetaPhi(tc->p, tc->theta, tc->phi); DVector3 pos(0.0, 0.0, tc->z_vertex); rt->Swim(pos, mom); double chisq_initial = ChiSq(rt->q, rt); double nhits_initial = Ngood_chisq_hits; chisq_final_vs_initial->Fill(chisq_initial,chisq_final); nhits_final_vs_initial->Fill(nhits_initial, nhits_final); #endif }