// $Id$ // // File: DTrackFitterALT1.cc // Created: Tue Sep 2 11:18:22 EDT 2008 // Creator: davidl // namespace{const char* GetMyID(){return "$Id$";}} #include #include #include #include #include using namespace jana; #include "GlueX.h" #include "DANA/DApplication.h" #include "DMagneticFieldStepper.h" #include "DTrackCandidate.h" #include "DTrackFitterALT1.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;} }; //------------------ // DTrackFitterALT1 (Constructor) //------------------ DTrackFitterALT1::DTrackFitterALT1(JEventLoop *loop):DTrackFitter(loop) { this->loop = loop; // 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; DEBUG_LEVEL = 0; 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; //SIGMA_FDC_ANODE = 100.0; //SIGMA_FDC_CATHODE = 100.0; 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:DEBUG_LEVEL", DEBUG_LEVEL); 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); // DReferenceTrajectory objects rt = new DReferenceTrajectory(bfield); 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 + 150.0; hit_based = false; //cout<<__FILE__<<":"<<__LINE__<<"-------------- Helical Fitter TRACKING --------------"<(loop->GetJApplication()); if(!dapp){ _DBG_<<"Cannot get DApplication from JEventLoop! (are you using a JApplication based program?)"<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"); chisq_vs_p_vs_theta = (TH2F*)gROOT->FindObject("chisq_vs_p_vs_theta"); 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); //if(!chisq_vs_p_vs_theta)chisq_vs_p_vs_theta = new TH2F("chisq_vs_p_vs_theta","#chi^{2}/dof map", 100, 0.9, 1.1, 100, 0.9, 1.1); dapp->Unlock(); } } //------------------ // DTrackFitterALT1 (Destructor) //------------------ DTrackFitterALT1::~DTrackFitterALT1() { if(rt)delete rt; if(tmprt)delete tmprt; } //------------------ // FitTrack //------------------ DTrackFitter::fit_status_t DTrackFitterALT1::FitTrack(void) { /// Fit a track candidate // Debug message if(DEBUG_LEVEL>2){ _DBG__; _DBG_<<"cdchits.size="<Swim(input_params.position(), input_params.momentum(), input_params.charge()); // Iterate over fitter until it converges or we reach the // maximum number of iterations double last_chisq = 1.0E6; int Niterations; for(Niterations=0; Niterations2)_DBG_<<"Fit succeeded ----- "<2)_DBG_<<"Unable to improve on input parameters (chisq="<2)_DBG_<<"Fit failed on iteration "<4){ if(DEBUG_LEVEL>2)_DBG_<<"Number of iterations >4. Trying to keep fit from last iteration... "<Fill(Niterations+1, chisq); dchisq_vs_pass->Fill(Niterations+1, last_chisq-chisq); } // If the chisq is too large, then consider it a hopeless cause if(chisq>1.0E4){ if(DEBUG_LEVEL>3)_DBG_<<"Fit chisq too large on iteration "<1)_DBG_<<" Niterations="<q>0 ? "+":"-")<<" now:"<<(rt->q>0 ? "-":"+")<<")"<FindByID(candidateid); if(tc==NULL){ _DBG_<<"Unable to find track candidate with id="<position(); const DVector3 &mom = tc->momentum(); DReferenceTrajectory *myrt = new DReferenceTrajectory(bfield); myrt->Swim(pos, mom, -tc->charge()); if(myrt->Nswim_steps==0){ if(DEBUG_LEVEL>2)_DBG_<<"No swim steps when swimming opposite charged track!"<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 } delete myrt; return track; } #endif //------------------ // ChiSq //------------------ double DTrackFitterALT1::ChiSq(fit_type_t fit_type, DReferenceTrajectory *rt, double *chisq_ptr, int *dof_ptr) { hitInfo hinfo; GetWiresShiftsErrs(fit_type, rt, hinfo); return ChiSq(rt, hinfo, chisqv, chisq_ptr, dof_ptr); } //------------------ // ChiSq //------------------ double DTrackFitterALT1::ChiSq(DMatrix &state, const swim_step_t *start_step, DReferenceTrajectory *rt, hitInfo &hinfo, vector &chisqv, double *chisq_ptr, int *dof_ptr) { /// Calculate the chi-squared for a track specified by state relative to the /// given reference trajectory. This is just a wrapper for /// ChiSq(DReferenceTrajectory *rt, vector &wires, vector &shifts, vector &errs, vector &chisqv) /// that accepts the state vector and re-swims the trajectory. // "v" direction is perpendicular to both the rt direction and the // x-direction. See LeastSquares() for more. DVector3 vdir = start_step->sdir.Cross(start_step->mom); vdir.SetMag(1.0); DVector3 pos = start_step->origin + state[state_x ][0]*start_step->sdir + state[state_v ][0]*vdir; DVector3 mom = state[state_px][0]*start_step->sdir + state[state_py][0]*start_step->tdir + state[state_pz][0]*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]="<2*hinfo.wires.size()) || (hinfo.shifts.size()!=0 && !use_shifts)){ _DBG_<<"Error! the wires, errs, and shifts vectors are out of alignment."<swim_steps[0].mom.Theta()*TMath::RadToDeg(); // --- CDC --- for(unsigned int i=0; iwire; hinfo.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==kWireBased){ // 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 hinfo.errs.push_back(0.8/sqrt(12.0)); // variance for evenly illuminated straw hinfo.u_dists.push_back(0.0); // placeholder hinfo.u_errs.push_back(0.0); // placeholder indicating no measurement along wire }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; hinfo.shifts.push_back(shift); hinfo.errs.push_back(SIGMA_CDC); hinfo.u_dists.push_back(0.0); // placeholder hinfo.u_errs.push_back(0.0); // placeholder indicating no measurement along wire } } // --- FDC --- for(unsigned int i=0; iwire; hinfo.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==kWireBased){ // 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 hinfo.errs.push_back(0.5/sqrt(12.0)); // variance for evenly illuminated cell - anode hinfo.u_errs.push_back(0.0); // variance for evenly illuminated cell - cathode hinfo.u_dists.push_back(0.0); }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; // Calculate angle dependent cathode resolution using theta in degrees (from resic_sigma_vs_angle.C macro) double fdc_cathode_sigma = 198.253 + theta_deg*(1.40683 + theta_deg*(-0.0998842 + theta_deg*(0.00780125))); fdc_cathode_sigma /= 10000.0; // convert from microns to cm hinfo.shifts.push_back(shift); hinfo.errs.push_back(SIGMA_FDC_ANODE); hinfo.u_dists.push_back(hit->s); hinfo.u_errs.push_back(fdc_cathode_sigma); //hinfo.u_errs.push_back(SIGMA_FDC_CATHODE); //hinfo.u_errs.push_back(0.0); } } // Copy the errors in errs and u_errs into all_errs. This is needed so we have an easy-to-access // list of the errors corresponding to each element in the chisqv vector. for(unsigned int i=0; ichisq = 1.0E6; this->Ndof = 0; // Make sure RT is not empty if(rt->Nswim_steps<1)return kFitFailed; // For fitting, we want to define a coordinate system very similar to the // Reference Trajectory coordinate system. The difference is that we want // the position to be defined in a plane perpendicular to the momentum. // The RT x-direction is in this plane, but the momentum itself lies // somewhere in the Y/Z plane so that neither Y nor Z makes a good choice // for the second postion dimension. We will call the second coordinate in // the perpendicular plane "v" which is the coordinate along the axis that // is perpendicular to both the x-direction and the momentum direction. swim_step_t &start_step = rt->swim_steps[0]; DVector3 pos = start_step.origin; DVector3 mom = start_step.mom; // Make list of wires hitInfo hinfo; GetWiresShiftsErrs(fit_type, rt, hinfo); // Get the chi-squared vector for the initial reference trajectory vector chisqv_initial; double initial_chisq; int initial_Ndof; double initial_chisq_per_dof = ChiSq(rt, hinfo, chisqv_initial, &initial_chisq, &initial_Ndof); // 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_pz ][0] = mom.Dot(start_step.udir); case 2: state[state_py ][0] = mom.Dot(start_step.tdir); case 1: state[state_px ][0] = mom.Dot(start_step.sdir); } // For the swimming below, we use a second reference trajectory so as // to preserve the original. Set the charge here. The reset 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_dpx = state; state_dpx[state_px][0] += LEAST_SQUARES_DP; deltas[state_px] = state_dpx[state_px][0] - state[state_px][0]; vector &chisqv_dpx_lo = chisqv_initial; vector chisqv_dpx_hi; double chisq_dpx = ChiSq(state_dpx, &start_step, tmprt, hinfo, chisqv_dpx_hi); // dpy : tweak by +/- 0.01 DMatrix state_dpy = state; state_dpy[state_py][0] += LEAST_SQUARES_DP; deltas[state_py] = state_dpy[state_py][0] - state[state_py][0]; vector &chisqv_dpy_lo = chisqv_initial; vector chisqv_dpy_hi; double chisq_dpy = ChiSq(state_dpy, &start_step, tmprt, hinfo, chisqv_dpy_hi); // dpz : tweak by +/- 0.01 DMatrix state_dpz = state; state_dpz[state_pz][0] += LEAST_SQUARES_DP; deltas[state_pz] = state_dpz[state_pz][0] - state[state_pz][0]; vector &chisqv_dpz_lo = chisqv_initial; vector chisqv_dpz_hi; double chisq_dpz = ChiSq(state_dpz, &start_step, tmprt, hinfo, chisqv_dpz_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, hinfo, 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, hinfo, chisqv_dx_hi); // This line just avoids a compiler warning if(DEBUG_LEVEL>4){ _DBG_<<"initial_chisq_per_dof="< good; unsigned int Ngood=0; unsigned int Nhits = chisqv_initial.size(); for(unsigned int i=0; i1.0 ? initial_chisq_per_dof:1.0); double sigma; sigma = chisqv_initial[i]; if(!finite(sigma) || fabs(sigma)>max){good.push_back(false); continue;} sigma = chisqv_dpx_hi[i]; if(!finite(sigma) || fabs(sigma)>max){good.push_back(false); continue;} sigma = chisqv_dpy_hi[i]; if(!finite(sigma) || fabs(sigma)>max){good.push_back(false); continue;} sigma = chisqv_dpz_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="<1E+18) which we can use to punt now. In reality, we do this to avoid // ROOT error messages about a matrix being singular when Ft*Vinv*F is inverted below. if(F.E2Norm()>1.0E18){ if(DEBUG_LEVEL>1){ _DBG_<<" -- F matrix E2Norm out of range(E2Norm="<1)_DBG_<<" -- B matrix invalid"< LEAST_SQUARES_MAX_E2NORM){ if(DEBUG_LEVEL>1){ _DBG_<<" -- B matrix E2Norm out of range(E2Norm="< new_chisqv; double chisq_per_dof = ChiSq(new_state, &start_step, tmprt, hinfo, new_chisqv); if(chisq_per_dof4)_DBG_<<" -- initial_chisq_per_dof="<chisq = initial_chisq; this->Ndof = initial_Ndof; return kFitNoImprovement; } // Re-create new_state using min_lambda for(int i=0; ichisq, &this->Ndof); 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="<