/* This file is part of MAUS: http://micewww.pp.rl.ac.uk:8080/projects/maus * * MAUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MAUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MAUS. If not, see . * */ // C headers #include #include // C++ headers #include #include #include #include #include #include // External libs headers #include "TROOT.h" // MAUS headers #include "src/common_cpp/Recon/SciFi/PatternRecognition.hh" #include "src/common_cpp/DataStructure/SimpleLine.hh" #include "src/common_cpp/DataStructure/SimpleCircle.hh" #include "src/common_cpp/DataStructure/SimpleHelix.hh" #include "src/common_cpp/DataStructure/ThreeVector.hh" namespace MAUS { PatternRecognition::PatternRecognition() { if (debug == 2) { _f_res = new ofstream(); _f_res->open("residuals.dat", std::ios::app); _f_res_good = new ofstream(); _f_res_good->open("residuals_good.dat", std::ios::app); _f_res_chosen = new ofstream(); _f_res_chosen->open("residuals_chosen.dat", std::ios::app); _f_trks = new ofstream(); _f_trks->open("tracks.dat", std::ios::app); } }; PatternRecognition::~PatternRecognition() { if (debug == 2) { if ( _f_res ) { _f_res->close(); delete _f_res; _f_res = NULL; } if ( _f_res_good ) { _f_res_good->close(); delete _f_res_good; _f_res_good = NULL; } if ( _f_res_chosen ) { _f_res_chosen->close(); delete _f_res_chosen; _f_res_chosen = NULL; } if ( _f_trks ) { _f_trks->close(); delete _f_trks; _f_trks = NULL; } } }; void PatternRecognition::process(const bool helical_pr_on, const bool straight_pr_on, SciFiEvent &evt) { set_helical_pr_on(helical_pr_on); set_straight_pr_on(straight_pr_on); if ( evt.spacepoints().size() > 0 ) { // Some setup evt.set_spacepoints_used_flag(false); SpacePoint2dPArray spnts_by_tracker(_n_trackers); spnts_by_tracker = sort_by_tracker(evt.spacepoints()); // Loop over trackers for ( int trker_no = 0; trker_no < _n_trackers; ++trker_no ) { // Split spacepoints according to which station they occured in SpacePoint2dPArray spnts_by_station(_n_stations); sort_by_station(spnts_by_tracker[trker_no], spnts_by_station); // Make the helical and straight tracks, depending on flags if ( _helical_pr_on ) { bool track_type = 1; make_all_tracks(track_type, trker_no, spnts_by_station, evt); } if ( _straight_pr_on ) { bool track_type = 0; make_all_tracks(track_type, trker_no, spnts_by_station, evt); } }// ~Loop over trackers std::cout << "Number of straight tracks found: " << evt.straightprtracks().size() << "\n\n"; std::cout << "Number of helical tracks found: " << evt.helicalprtracks().size() << "\n\n"; } else { std::cout << "No spacepoints in event" << std::endl; } }; void PatternRecognition::make_all_tracks(const bool track_type, const int trker_no, SpacePoint2dPArray &spnts_by_station, SciFiEvent &evt) { // Count how many stations have at least one *unused* spacepoint int num_stations_hit = num_stations_with_unused_spnts(spnts_by_station); // Make the tracks if (num_stations_hit == 5) { std::vector strks; std::vector htrks; make_5tracks(track_type, spnts_by_station, strks, htrks); add_tracks(trker_no, strks, htrks, evt); } num_stations_hit = num_stations_with_unused_spnts(spnts_by_station); if (num_stations_hit > 3) { std::vector strks; std::vector htrks; make_4tracks(track_type, spnts_by_station, strks, htrks); add_tracks(trker_no, strks, htrks, evt); } num_stations_hit = num_stations_with_unused_spnts(spnts_by_station); if (num_stations_hit > 2) { std::vector strks; std::vector htrks; make_3tracks(track_type, spnts_by_station, strks, htrks); add_tracks(trker_no, strks, htrks, evt); } } void PatternRecognition::add_tracks(const int trker_no, std::vector &strks, std::vector &htrks, SciFiEvent &evt ) { for ( int i = 0; i < static_cast(strks.size()); ++i ) { strks[i].set_tracker(trker_no); evt.add_straightprtrack(strks[i]); } for ( int i = 0; i < static_cast(htrks.size()); ++i ) { htrks[i].set_tracker(trker_no); evt.add_helicalprtrack(htrks[i]); } } void PatternRecognition::make_5tracks(const bool track_type, SpacePoint2dPArray &spnts_by_station, std::vector &strks, std::vector &htrks) { if ( debug > 0 ) std::cout << "Making 5 point tracks" << std::endl; int num_points = 5; std::vector ignore_stations; // A zero size vector sets that all stations are to be used if ( track_type == 0 ) make_straight_tracks(num_points, ignore_stations, spnts_by_station, strks); if ( track_type == 1 ) make_helix(num_points, ignore_stations, spnts_by_station, htrks); if ( debug > 0 ) std::cout << "Finished making 5 pt tracks" << std::endl; } // ~make_spr_5pt(...) void PatternRecognition::make_4tracks(const bool track_type, SpacePoint2dPArray &spnts_by_station, std::vector &strks, std::vector &htrks) { if ( debug > 0 ) std::cout << "Making 4 point tracks" << std::endl; int num_points = 4; // Count how many stations have at least one *unused* spacepoint int num_stations_hit = num_stations_with_unused_spnts(spnts_by_station); // Call make_tracks with parameters depending on how many stations have unused spacepoints if ( num_stations_hit == 5 ) { if ( debug > 0 ) std::cout << "4pt track: 5 stations with unused spacepoints" << std::endl; for (int i = 0; i < 5; ++i) { // Loop of stations, ignoring each one in turn // Recount how many stations have at least one unused spacepoint num_stations_hit = num_stations_with_unused_spnts(spnts_by_station); // If there are enough occupied stations left to make a 4 point track, keep making tracks if ( num_stations_hit >= num_points ) { std::vector ignore_stations(1, i); if ( track_type == 0 ) make_straight_tracks(num_points, ignore_stations, spnts_by_station, strks); if ( track_type == 1 ) make_helix(num_points, ignore_stations, spnts_by_station, htrks); } else { break; } } // ~Loop of stations, ignoring each one in turn } else if ( num_stations_hit == 4 ) { if ( debug > 0 ) std::cout << "4pt track: 4 stations with unused spacepoints" << std::endl; // Find out which station has no unused hits (1st entry in stations_not_hit vector) std::vector stations_hit, stations_not_hit; stations_with_unused_spnts(spnts_by_station, stations_hit, stations_not_hit); // Make the tracks if ( static_cast(stations_not_hit.size()) == 1 ) { if ( track_type == 0 ) make_straight_tracks(num_points, stations_not_hit, spnts_by_station, strks); if ( track_type == 1 ) make_helix(num_points, stations_not_hit, spnts_by_station, htrks); } else { if ( debug > 0 ) std::cerr << "Wrong number of stations without spacepoints aborting 4 pt track.\n"; } } else if ( num_stations_hit < 4 ) { if ( debug > 0 ) std::cout << "Not enough unused spacepoints, quiting 4 point track." << std::endl; } else if ( num_stations_hit > 6 ) { if ( debug > 0 ) std::cerr << "Wrong number of stations with spacepoints, aborting 4 pt track.\n"; } if ( debug > 0 ) std::cout << "Finished making 4 pt tracks" << std::endl; } // ~make_straight_4tracks(...) void PatternRecognition::make_3tracks(const bool track_type, SpacePoint2dPArray &spnts_by_station, std::vector &strks, std::vector &htrks) { if ( debug > 0 ) std::cout << "Making 3 point track" << std::endl; int num_points = 3; // Count how many stations have at least one *unused* spacepoint int num_stations_hit = num_stations_with_unused_spnts(spnts_by_station); bool sufficient_hit_stations = true; // Call make_tracks with parameters depending on how many stations have unused spacepoints if ( num_stations_hit == 5 ) { if ( debug > 0 ) std::cout << "3pt track: 5 stations with unused spacepoints" << std::endl; for (int i = 0; i < 4; ++i) { // Loop of first station to ignore if ( sufficient_hit_stations ) { for (int j = i + 1; j < 5; ++j) { // Loop of second station to ignore if ( sufficient_hit_stations ) { // Recount how many stations have at least one unused spacepoint num_stations_hit = num_stations_with_unused_spnts(spnts_by_station); // If there are enough occupied stations left to make a 3pt track, keep making tracks if ( num_stations_hit >= num_points ) { std::vector ignore_stations; ignore_stations.push_back(i); ignore_stations.push_back(j); if ( track_type == 0 ) make_straight_tracks(num_points, ignore_stations, spnts_by_station, strks); if ( track_type == 1 ) make_helix(num_points, ignore_stations, spnts_by_station, htrks); } else { sufficient_hit_stations = false; } } // ~if ( sufficient_hit_stations ) } // ~Loop of second station to ignore } // ~if ( sufficient_hit_stations ) } // ~Loop of first station to ignore } else if ( num_stations_hit == 4 ) { if ( debug > 0 ) std::cout << "3pt track: 4 stations with unused spacepoints" << std::endl; // Find out which station has no unused hits (1st entry in stations_not_hit vector) std::vector stations_hit, stations_not_hit; stations_with_unused_spnts(spnts_by_station, stations_hit, stations_not_hit); std::vector ignore_stations; // Make the tracks if ( static_cast(stations_not_hit.size()) == 1 ) { for (int i = 0; i < 5; ++i) { // Loop of stations, ignoring each one in turn // Recount how many stations have at least one unused spacepoint num_stations_hit = num_stations_with_unused_spnts(spnts_by_station); // If there are enough occupied stations left to make a 4 point track, keep making tracks if ( num_stations_hit >= num_points ) { ignore_stations.clear(); if ( stations_not_hit[0] != i ) { // Don't send the same 2 ignore stations ignore_stations.push_back(stations_not_hit[0]); ignore_stations.push_back(i); if ( track_type == 0 ) make_straight_tracks(num_points, ignore_stations, spnts_by_station, strks); if ( track_type == 1 ) make_helix(num_points, ignore_stations, spnts_by_station, htrks); } } else { break; } } } } else if ( num_stations_hit == 3 ) { if ( debug > 0 ) std::cout << "3pt track: 3 stations with unused spacepoints" << std::endl; // Find out which station has no unused hits (1st entry in stations_not_hit vector) std::vector stations_hit, stations_not_hit; stations_with_unused_spnts(spnts_by_station, stations_hit, stations_not_hit); // Make the tracks if ( static_cast(stations_not_hit.size()) == 2 ) { if ( track_type == 0 ) make_straight_tracks(num_points, stations_not_hit, spnts_by_station, strks); if ( track_type == 1 ) make_helix(num_points, stations_not_hit, spnts_by_station, htrks); } else { if ( debug > 0 ) { std::cerr << "Wrong number of stations without spacepoints, "; std::cerr << "aborting 3 pt track." << std::endl; } } } else if ( num_stations_hit < 3 ) { if ( debug > 0 ) std::cout << "Not enough unused spacepoints, quiting 3 point track." << std::endl; } else if ( num_stations_hit > 6 ) { if ( debug > 0 ) std::cerr << "Wrong number of stations with spacepoints, aborting 3 pt track." << std::endl; } if ( debug > 0 ) std::cout << "Finished making 3 pt tracks" << std::endl; } // ~make_straight_3tracks(...) void PatternRecognition::make_straight_tracks(const int num_points, const std::vector ignore_stations, SpacePoint2dPArray &spnts_by_station, std::vector &strks) { // Set inner and outer stations int outer_st_num = -1, inner_st_num = -1; set_end_stations(ignore_stations, outer_st_num, inner_st_num); if (static_cast(spnts_by_station.size()) == _n_stations && outer_st_num > -1 && outer_st_num < _n_stations && inner_st_num > -1 && inner_st_num < _n_stations) { // Loop over spacepoints in outer station for ( unsigned int outer_sp = 0; outer_sp < spnts_by_station[outer_st_num].size(); ++outer_sp ) { // Check the outer spacepoint is unused and enough stations are left with unused sp if ( !spnts_by_station[outer_st_num][outer_sp]->get_used() && num_stations_with_unused_spnts(spnts_by_station) >= num_points) { // Loop over spacepoints in inner station for ( unsigned int inner_sp = 0; inner_sp < spnts_by_station[inner_st_num].size(); ++inner_sp ) { // Check the inner spacepoint is unused and enough stations are left with unused sp if ( !spnts_by_station[inner_st_num][inner_sp]->get_used() && num_stations_with_unused_spnts(spnts_by_station) >= num_points ) { // Vector to hold the good spacepoints in each station std::vector good_spnts; // good_spnts.resize(num_points); // Set variables to hold which stations are to be ignored int ignore_st_1 = -1, ignore_st_2 = -1; set_ignore_stations(ignore_stations, ignore_st_1, ignore_st_2); // Draw a straight line between spacepoints in outer most and inner most stations SimpleLine line_x, line_y; draw_line(spnts_by_station[outer_st_num][outer_sp], spnts_by_station[inner_st_num][inner_sp], line_x, line_y); // Loop over intermediate stations and compare spacepoints with the line for ( int st_num = inner_st_num + 1; st_num < outer_st_num; ++st_num ) { if (st_num != ignore_st_1 && st_num != ignore_st_2) { // A large number so initial value is set as best first double delta_sq = 1000000; int best_sp = -1; // Loop over spacepoints for ( unsigned int sp_no = 0; sp_no < spnts_by_station[st_num].size(); ++sp_no ) { // If the spacepoint has not already been used in a track fit if ( !spnts_by_station[st_num][sp_no]->get_used() ) { SciFiSpacePoint *sp = spnts_by_station[st_num][sp_no]; double dx = 0, dy = 0; calc_residual(sp, line_x, line_y, dx, dy); if ( debug > 1 ) *_f_res << st_num << "\t" << num_points << "\t" << dx << "\t" << dy << "\n"; // Apply roadcuts & find the spoints with the smallest residuals for the line if ( fabs(dx) < _res_cut && fabs(dy) < _res_cut ) { if ( debug > 1 ) { *_f_res_good << st_num << "\t" << num_points << "\t"; *_f_res_good << dx << "\t" << dy << "\n"; } if ( delta_sq > (dx*dx + dy*dy) ) delta_sq = dx*dx + dy*dy; best_sp = sp_no; // add_residuals(true, dx, dy, residuals); } // ~If pass roadcuts and beats previous best fit point } // ~If spacepoint is unused } // ~Loop over spacepoints // Push back the best spacepoint found for the current station if (best_sp > -1) { SciFiSpacePoint * sp = spnts_by_station[st_num][best_sp]; good_spnts.push_back(sp); double dx = 0, dy = 0; calc_residual(sp, line_x, line_y, dx, dy); if ( debug > 1 ) { *_f_res_chosen << st_num << "\t" << num_points << "\t"; *_f_res_chosen << dx << "\t" << dy << "\n"; } }// ~if (counter > 0) } // ~if (st_num != ignore_station) } // ~Loop over intermediate stations // Clear the line objects so we can reuse them line_x.clear(); line_y.clear(); // Check we have at least 1 good spacepoint in each of the intermediate stations if ( static_cast(good_spnts.size()) > (num_points - 3) ) { good_spnts.insert(good_spnts.begin(), spnts_by_station[inner_st_num][inner_sp]); good_spnts.push_back(spnts_by_station[outer_st_num][outer_sp]); std::vector x, x_err, y, y_err, z; for ( int i = 0; i < static_cast(good_spnts.size()); ++i ) { x.push_back(good_spnts[i]->get_position().x()); y.push_back(good_spnts[i]->get_position().y()); z.push_back(good_spnts[i]->get_position().z()); // The error on the position measurements of sp in a tracker (same in x and y) double sd = -1.0; if ( good_spnts[i]->get_station() == 5 ) sd = _sd_5; else sd = _sd_1to4; x_err.push_back(sd); y_err.push_back(sd); } // Fit track SimpleLine line_x, line_y; linear_fit(z, x, x_err, line_x); linear_fit(z, y, y_err, line_y); // Check track passes chisq test, then create SciFiStraightPRTrack if ( ( line_x.get_chisq() / ( num_points - 2 ) < _chisq_cut ) && ( line_y.get_chisq() / ( num_points - 2 ) < _chisq_cut ) ) { if ( debug > 0 ) std::cout << "** chisq test passed, adding " << num_points << "pt track **\n"; SciFiStraightPRTrack track(-1, num_points, line_x, line_y); if ( debug > 0 ) { std::cout << "x0 = " << track.get_x0() << "mx = " << track.get_mx(); std::cout << "y0 = " << track.get_y0() << "my = " << track.get_my() << std::endl; } // *_f_trks << num_points << "\t" << track.get_x0() << "\t" << track.get_mx(); // *_f_trks << "\t" << track.get_x_chisq() << "\t" << track.get_y0() << "\t"; // *_f_trks << track.get_my() << "\t" << track.get_y_chisq() << "\t" << 1 << "\n"; // Set all the good sp to used and convert pointers to variables std::vector good_spnts_variables; good_spnts_variables.resize(good_spnts.size()); for ( int i = 0; i < static_cast(good_spnts.size()); ++i ) { good_spnts[i]->set_used(true); good_spnts_variables[i] = *good_spnts[i]; } // Populate the sp of the track and then push the track back into the strks vector track.set_spacepoints(good_spnts_variables); strks.push_back(track); } else { if ( debug > 0 ) { std::cout << "x_chisq = " << line_x.get_chisq(); std::cout << "\ty_chisq = " << line_y.get_chisq() << std::endl; std::cout << "chisq test failed, " << num_points << "pt track rejected\n"; } SciFiStraightPRTrack bad_track(-1, num_points, line_x, line_y); // *_f_trks << num_points << "\t" << bad_track.get_x0() << "\t"; // *_f_trks << bad_track.get_mx() << "\t" << bad_track.get_x_chisq() << "\t"; // *_f_trks << bad_track.get_y0() << "\t" << bad_track.get_my() << "\t"; // *_f_trks << bad_track.get_y_chisq() << "\t" << 0 << "\n"; } // ~Check track passes chisq test } // ~ if ( good_spnts.size() > 1 ) } else { // std::cout << "...no" << std::endl; }// ~Check the inner spacepoint is unused } // ~Loop over sp in station 1 } else { // std::cout << "...no" << std::endl; }// ~Check the outer spacepoint is unused } // ~Loop over sp in station 5 } else { if ( debug > 0 ) std::cerr << "Bad spnts_by_station passed, aborting make_straight_tracks.\n"; } } // ~make_straight_tracks(...) void PatternRecognition::linear_fit(const std::vector &_x, const std::vector &_y, const std::vector &_y_err, SimpleLine &line) { int num_points = static_cast(_x.size()); CLHEP::HepMatrix A(num_points, 2); // rows, columns CLHEP::HepMatrix V(num_points, num_points); // error matrix CLHEP::HepMatrix Y(num_points, 1); // measurements for ( int i = 0; i < static_cast(_x.size()); ++i ) { // std::cout <<"( " << _x[i] << "," << _y[i] << " )" << std::endl; A[i][0] = 1; A[i][1] = _x[i]; V[i][i] = ( _y_err[i] * _y_err[i] ); Y[i][0] = _y[i]; } CLHEP::HepMatrix At, tmpy, yparams; int ierr; V.invert(ierr); At = A.T(); tmpy = At * V * A; tmpy.invert(ierr); yparams = tmpy * At * V * Y; line.set_c(yparams[0][0]); line.set_m(yparams[1][0]); line.set_c_err(sqrt(tmpy[0][0])); line.set_m_err(sqrt(tmpy[1][1])); CLHEP::HepMatrix C, result; C = Y - (A * yparams); result = C.T() * V * C; line.set_chisq(result[0][0]); line.set_chisq_dof(result[0][0] / num_points); } // ~linear_fit(...) void PatternRecognition::make_helix(const int num_points, const std::vector ignore_stations, SpacePoint2dPArray &spnts_by_station, std::vector &htrks) { // Set inner and outer stations int outer_st_num = -1, inner_st_num = -1, mid_st_num = -1; bool success = set_seed_stations(ignore_stations, outer_st_num, inner_st_num, mid_st_num); if ( !success ) { std::cerr << "Failed to set seed station, aborting making helices" << std::endl; return; } // ** Beginning nested loops to find unused spacepoints from each station available. ** // Loop over spacepoints in outer station for ( unsigned int outer_sp = 0; outer_sp < spnts_by_station[outer_st_num].size(); ++outer_sp ) { // Check the outer spacepoint is unused and enough stations are left with unused sp if ( !spnts_by_station[outer_st_num][outer_sp]->get_used() && num_stations_with_unused_spnts(spnts_by_station) >= num_points) { // Loop over spacepoints in inner station for ( unsigned int inner_sp = 0; inner_sp < spnts_by_station[inner_st_num].size(); ++inner_sp ) { // Check the inner spacepoint is unused and enough stations are left with unused sp if ( !spnts_by_station[inner_st_num][inner_sp]->get_used() && !spnts_by_station[outer_st_num][outer_sp]->get_used() && num_stations_with_unused_spnts(spnts_by_station) >= num_points ) { // Loop over spacepoints in middle station for ( unsigned int mid_sp = 0; mid_sp < spnts_by_station[mid_st_num].size(); ++mid_sp ) { // Check intermediate spnts are unused and enough stations are left with unused spnts if ( !spnts_by_station[mid_st_num][mid_sp]->get_used() && !spnts_by_station[inner_st_num][inner_sp]->get_used() && !spnts_by_station[outer_st_num][outer_sp]->get_used() && num_stations_with_unused_spnts(spnts_by_station) >= num_points ) { // Vector to hold the good spacepoints in each station std::vector good_spnts; // Set variables to hold which stations are to be ignored int ignore_st_1 = -1, ignore_st_2 = -1; set_ignore_stations(ignore_stations, ignore_st_1, ignore_st_2); // Loop over other intermediate stations so that can try adding them to the circle for ( int st_num = inner_st_num + 1; st_num < outer_st_num; ++st_num ) { if (st_num != mid_st_num && st_num != ignore_st_1 && st_num != ignore_st_2) { for (unsigned int sp_no = 0; sp_no < spnts_by_station[st_num].size(); ++sp_no) { // If the spacepoint has not already been used in a track fit if ( !spnts_by_station[st_num][sp_no]->get_used() ) { good_spnts.push_back(spnts_by_station[st_num][sp_no]); } } // ~loop over intermediate station sp } // ~if (st_num != ignore_station) } // ~Loop over intermediate stations not used in initial circle_fit // Fill the rest of the good_spnts vector if ( good_spnts.size() > 0 && good_spnts[0]->get_station() > mid_st_num+1 ) good_spnts.insert(good_spnts.begin(), spnts_by_station[mid_st_num][mid_sp]); else if ( good_spnts.size() > 0 && good_spnts[0]->get_station() < mid_st_num+1 ) good_spnts.insert(good_spnts.begin() + 1, spnts_by_station[mid_st_num][mid_sp]); else good_spnts.push_back(spnts_by_station[mid_st_num][mid_sp]); // Check we have at least 1 good spacepoint in each of the intermediate stations if ( static_cast(good_spnts.size()) >= (num_points - 3) ) { good_spnts.insert(good_spnts.begin(), spnts_by_station[inner_st_num][inner_sp]); good_spnts.push_back(spnts_by_station[outer_st_num][outer_sp]); // Perform a circle fit now that we have found a set of spacepoints SimpleCircle circle; bool good_radius = circle_fit(good_spnts, circle); // If the radius calculated is too large, force loop to iterate from here if ( !good_radius ) continue; // Check circle chisq test passes, then perform s-z fit if ( circle.get_chisq() / ( num_points - 2 ) < _chisq_cut ) { // std::cerr << "Found a good circle using spacepoints:\n"; for (unsigned int i = 0; i < good_spnts.size(); ++i) { ThreeVector pos = good_spnts[i]->get_position(); std::cerr << pos.x() << " " << pos.y() << " " << pos.z() << std::endl; } /* std::cerr << " circle_x0 is " << circle.get_x0() << std::endl; std::cerr << " circle_y0 is " << circle.get_y0() << std::endl; std::cerr << " circle_R is " << circle.get_R() << std::endl; std::cerr << " circle_chi2 is " << circle.get_chisq() << std::endl; */ SimpleLine line_sz; std::vector dphi; // to hold change between turning angles double phi_0; // initial turning angle // Perform s-z fit calculate_dipangle(good_spnts, circle, dphi, line_sz, phi_0); /* std::cerr << "line_sz_c is " << line_sz.get_c() << std::endl; std::cerr << "line_sz_m is " << line_sz.get_m() << std::endl; std::cerr << "line_sz_chisq is " << line_sz.get_chisq() << std::endl; */ // Check linear fit passes chisq test, then perform make a helical track if ( line_sz.get_chisq() / ( num_points - 2 ) < _sz_chisq_cut ) { // double pt = circle.get_R() * 1.2; // double pz = pt / line_sz.get_m(); if ( debug > 0 ) std::cout << "dsdz = " << line_sz.get_m() << std:: endl; double psi_0 = phi_0 + (CLHEP::pi / 2); SciFiHelicalPRTrack track(-1, num_points, good_spnts[0]->get_position(), phi_0, psi_0, circle, line_sz); track.set_phi_i(dphi); /* for ( unsigned int i = 0; i < dphi.size(); ++i ) { std::cerr << "1phi_i[" << i << "] = " << dphi[i] << std::endl; std::cerr << "2phi_i[" << i << "] = " << track.get_phi_i()[i] << std::endl; }*/ // Set all the good sp to used and convert pointers to variables std::vector good_spnts_variables; good_spnts_variables.resize(good_spnts.size()); for ( int i = 0; i < static_cast(good_spnts.size()); ++i ) { good_spnts[i]->set_used(true); good_spnts_variables[i] = *good_spnts[i]; } // Populate the sp of the track and then push the track back into trks vector track.set_spacepoints(good_spnts_variables); htrks.push_back(track); } // ~Check s-z line passes chisq test } // ~Check circle passes chisq test } // ~if enough spacepoints are found for fit (must be at least 3) } // ~if middle station sp unused } // ~Loop over middle station spacepoints } // ~If inner station spacepoint is unused } // ~Loop over inner station spacepoints } // ~if outer station spacepoint is unused } // ~Loop over outer station spacepoints } // ~make_helix(...) bool PatternRecognition::circle_fit(const std::vector &spnts, SimpleCircle &circle) { int num_points = static_cast(spnts.size()); CLHEP::HepMatrix A(num_points, 3); // rows, columns CLHEP::HepMatrix V(num_points, num_points); // error matrix CLHEP::HepMatrix K(num_points, 1); for ( int i = 0; i < static_cast(spnts.size()); ++i ) { // This part will change once I figure out proper errors double sd = -1.0; if ( spnts[i]->get_station() == 5 ) sd = _sd_5; else sd = _sd_1to4; double x_i = spnts[i]->get_position().x(); double y_i = spnts[i]->get_position().y(); A[i][0] = ( x_i * x_i ) + ( y_i * y_i ); A[i][1] = x_i; A[i][2] = y_i; V[i][i] = ( sd * sd ); K[i][0] = 1.; } CLHEP::HepMatrix At, tmpx, tmp_params; int ierr; V.invert(ierr); At = A.T(); tmpx = At * V * A; tmpx.invert(ierr); tmp_params = tmpx * At * V * K; // These values will be used for delta_R calculation double alpha, beta, gamma; alpha = tmp_params[0][0]; beta = tmp_params[1][0]; gamma = tmp_params[2][0]; // Convert the linear parameters into the circle center and radius double x0, y0, R; x0 = (-1*beta) / (2 * alpha); y0 = (-1*gamma) / (2 * alpha); if ( ((4 * alpha) + (beta * beta) + (gamma * gamma)) < 0 ) R = 0; else R = sqrt((4 * alpha) + (beta * beta) + (gamma * gamma)) / (2 * alpha); if ( debug > 0 ) { std::cout << "alpha = " << alpha << std::endl; std::cout << "beta = " << beta << std::endl; std::cout << "gamma = " << gamma << std::endl; if ( R < 0. ) std::cout << "R was < 0 geometrically but taking abs_val for physical correctness\n"; } R = fabs(R); if (R > 150) return false; // Can not be larger than 150mm or the track is not contained in tracker circle.set_x0(x0); circle.set_y0(y0); circle.set_R(R); /* circle.set_x0_err(x0_err); circle.set_y0_err(y0_err); circle.set_R_err(R_err); */ // Stored to be used for delta_R calculation circle.set_alpha(alpha); circle.set_beta(beta); circle.set_gamma(gamma); // circle.set_alpha_err(alpha_err); // circle.set_beta_err(beta_err); // circle.set_gamma_err(gamma_err); CLHEP::HepMatrix C, result; C = K - (A * tmp_params); result = C.T() * V * C; double chi2 = result[0][0]; circle.set_chisq(chi2); // should I leave this un-reduced? return true; } // ~circle_fit(...) void PatternRecognition::calculate_dipangle(const std::vector &spnts, const SimpleCircle &circle, std::vector &dphi, SimpleLine &line_sz, double &phi_0) { // For the linear fit in s-z, we care about the change in z vs change in s // So here we calculate the values dz_i and phi_i (because ds_i = R * phi_i) std::vector dz; std::vector dphi_err; // Calculate phi_0, the rotation when moving from x to x' phi_0 = calc_turning_angle(spnts[0]->get_position().x(), spnts[0]->get_position().y(), circle); // Loop over spacepoints for ( int i = 1; i < static_cast(spnts.size()); ++i ) { dz.push_back(spnts[i]->get_position().z() - spnts[0]->get_position().z()); // theta_i is defined as phi_i + phi_0 i.e. the turning angle wrt the x (not x') axis double theta_i = calc_turning_angle(spnts[i]->get_position().x(), spnts[i]->get_position().y(), circle); // phi_i is defined as the turning angle wrt the x' axis, given by theta_i - phi_0 dphi.push_back(theta_i - phi_0); // std::cerr << "Pushed " << theta_i - phi_0 << " into dphi, size is " << dphi.size() << "\n"; // Set the error on phi double sd_phi = -1.0; if ( (spnts[i]->get_station() == 5) ) sd_phi = _sd_phi_5; else sd_phi = _sd_phi_1to4; dphi_err.push_back(sd_phi); } // ~Loop over spacepoints // Correct dphi for 2pi rotations bool dphi_ok = turns_between_stations(dz, dphi); // Use the dphi to calculate the ds by multiplying each element of dphi by R if ( dphi_ok ) { std::vector ds; dphi_to_ds(circle.get_R(), dphi, ds); /* if ( debug > 0 ) { for ( unsigned int i = 0; i < ds.size(); i++ ) { std::cerr << "ds = " << ds[i] << ", dz = " << dz[i] << std::endl; } } */ // Peform a linear fit in s - z linear_fit(dz, ds, dphi_err, line_sz); // Take ds_err to be dphi_err (is this true??) } } // ~calculate_dipangle(...) double PatternRecognition::calc_turning_angle(double xpos, double ypos, const SimpleCircle &circle) { // Note this function returns phi_i + phi_0, unless using x0, y0 in which case it returns phi_0 double angle = atan2(ypos - circle.get_y0(), xpos - circle.get_x0()); if ( angle < 0. ) angle += 2. * CLHEP::pi; if ( debug > 0 ) std::cout << "Turning angle from circle fit = " << angle << std::endl; return angle; } // ~calculate_phi(...) bool PatternRecognition::turns_between_stations(const std::vector &dz, std::vector &dphi) { // Make sure that you have enough points to make a line (2) if ( dz.size() < 2 || dphi.size() < 2 ) return false; for ( int n = 0; n < 2; ++n ) { for ( int i = 0; i < static_cast(dphi.size()) - 1; ++i ) { int j = i + 1; if ( dphi[i] < 0 ) dphi[i] += 2. * CLHEP::pi; if ( dphi[j] < 0 ) dphi[j] += 2. * CLHEP::pi; if ( dphi[j] < dphi[i] ) dphi[j] += 2. * CLHEP::pi; double z_ratio = dz[j] / dz[i]; double phi_ratio = dphi[j] / dphi[i]; if ( fabs(phi_ratio - z_ratio) / z_ratio > _AB_cut ) { // try bool passed_cut = AB_ratio(dphi[i], dphi[j], dz[i], dz[j]); if ( !passed_cut ) return false; } } } return true; } // ~turns_between_stations(...) bool PatternRecognition::AB_ratio(double &dphi_ji, double &dphi_kj, double dz_ji, double dz_kj) { for ( int n = 0; n < 10; ++n ) { for ( int m = 0; m < 10; ++m ) { // std::cerr << "n is " << n << " and m is " << m << std::endl; double A, B; A = ( dphi_kj + ( 2 * n * CLHEP::pi ) ) / ( dphi_ji + ( 2 * m * CLHEP::pi ) ); // phi_ratio B = dz_kj / dz_ji; // z_ratio // std::cerr << "| A - B | / B = " << fabs(A - B)/B; // std::cerr << ", new phi_i = " << dphi_ji + ( 2 * m * CLHEP::pi ); // std::cerr<< ", new phi_j = " << dphi_kj + ( 2 * n * CLHEP::pi ) << std::endl; if ( fabs(A - B) / B < _AB_cut ) { dphi_kj += 2 * n * CLHEP::pi; dphi_ji += 2 * m * CLHEP::pi; // std::cerr << "Success: n = " << n << " m = " << m << std::endl; // std::cerr << "| A - B | / B = " << fabs(A - B)/B << " and AB_cut = " << _AB_cut << "\n"; return true; } } // end m loop } // end n loop return false; // Return false if _ABcut is never satisfied } // ~AB_ratio(...) void PatternRecognition::dphi_to_ds(double R, const std::vector &dphi, std::vector &ds) { // This function performs scaler multiplication on the input vector. for ( int i = 0; i < static_cast(dphi.size()); ++i ) { double ds_ji = dphi[i] * R; ds.push_back(ds_ji); } } // ~dphi_to_ds(...) bool PatternRecognition::check_time_consistency(const std::vector good_spnts) { double dT_first, dT_last; /* Waiting for Spacepoints to have time added **** double dT_first = good_spnts.front()->get_time(); double dT_last = good_spnts.back()->get_time(); */ double dZ = fabs(good_spnts.back()->get_position().z() - good_spnts.front()->get_position().z()); double dS; if ( _straight_pr_on && !_helical_pr_on ) // If you are ONLY looking at straight tracks dS = dZ; else if ( _helical_pr_on ) // if you are trying to reconstruc EITHER straight OR helical tracks dS = dZ * _Pt_max / _Pz_min; // _Pz_min is a guess right now. (both defined in header) double longest_allowed_time = dS / CLHEP::c_light; if ( fabs(dT_last - dT_first) > longest_allowed_time ) return false; else return true; } // For linear Pattern Recognition use bool PatternRecognition::set_end_stations(const std::vector ignore_stations, int &outer_st_num, int &inner_st_num) { if ( static_cast(ignore_stations.size()) == 0 ) { // 5pt track case outer_st_num = 4; inner_st_num = 0; } else if ( static_cast(ignore_stations.size()) == 1 ) { // 4pt track case // Check a valid station number has been supplied bool ok = false; for ( int i = 0; i < 5; ++i ) { if ( ignore_stations[0] == i ) ok = true; } if ( !ok ) { if ( debug > 0 ) std::cerr << "Error: Invalid ignore station argument." << std::endl; return false; } // Set outer station number if ( ignore_stations[0] != 4 ) outer_st_num = 4; else outer_st_num = 3; // Set inner station number if ( ignore_stations[0] != 0 ) inner_st_num = 0; else inner_st_num = 1; } else if ( static_cast(ignore_stations.size()) == 2 ) { // 3pt track case // Check valid station numbers have been supplied bool ok0 = false; bool ok1 = false; for ( int i = 0; i < 5; ++i ) { if ( ignore_stations[0] == i ) ok0 = true; if ( ignore_stations[1] == i ) ok1 = true; } if ( ignore_stations[0] == ignore_stations[1] ) ok0 = false; if ( !ok0 || !ok1 ) { if ( debug > 0 ) std::cerr << "Error: Invalid ignore station argument." << std::endl; return false; } // Set outer station number if ( ignore_stations[0] != 4 && ignore_stations[1] != 4 ) outer_st_num = 4; else if ( ignore_stations[0] != 3 && ignore_stations[1] != 3) outer_st_num = 3; else outer_st_num = 2; // Set inner station number if ( ignore_stations[0] != 0 && ignore_stations[1] != 0 ) inner_st_num = 0; else if ( ignore_stations[0] != 1 && ignore_stations[1] != 1 ) inner_st_num = 1; else inner_st_num = 2; } else { if ( debug > 0 ) std::cerr << "Error: Invalid ignore station argument." << std::endl; return false; } return true; } // ~set_end_stations(...) // For helical Pattern Recognition use bool PatternRecognition::set_seed_stations(const std::vector ignore_stations, int &outer_st_num, int &inner_st_num, int &mid_st_num) { if ( static_cast(ignore_stations.size()) == 0 ) { // 5pt track case outer_st_num = 4; inner_st_num = 0; mid_st_num = 2; } else if ( static_cast(ignore_stations.size()) == 1 ) { // 4pt track case // Check a valid station number has been supplied bool ok = false; for ( int i = 0; i < 5; ++i ) { if ( ignore_stations[0] == i ) ok = true; } if ( !ok ) { if ( debug > 0 ) std::cerr << "Error: Invalid ignore station argument." << std::endl; return false; } // Set outer station number if ( ignore_stations[0] != 4 ) outer_st_num = 4; else outer_st_num = 3; // Set inner station number if ( ignore_stations[0] != 0 ) inner_st_num = 0; else inner_st_num = 1; // Set middle station number if ( ignore_stations[0] != 2 ) mid_st_num = 2; else mid_st_num = 1; } else if ( static_cast(ignore_stations.size()) == 2 ) { // 3pt track case // Check valid station numbers have been supplied bool ok0 = false; bool ok1 = false; for ( int i = 0; i < 5; ++i ) { if ( ignore_stations[0] == i ) ok0 = true; if ( ignore_stations[1] == i ) ok1 = true; } if ( ignore_stations[0] == ignore_stations[1] ) ok0 = false; if ( !ok0 || !ok1 ) { if ( debug > 0 ) std::cerr << "Error: Invalid ignore station argument." << std::endl; return false; } if ( ignore_stations[0] == 4 || ignore_stations[1] == 4 ) { // 1 of ignore stats is 4 if ( ignore_stations[0] == 3 || ignore_stations[1] == 3 ) { outer_st_num = 2; mid_st_num = 1; inner_st_num = 0; } else if ( ignore_stations[0] == 2 || ignore_stations[1] == 2 ) { outer_st_num = 3; mid_st_num = 1; inner_st_num = 0; } else if ( ignore_stations[0] == 1 || ignore_stations[1] == 1 ) { outer_st_num = 3; mid_st_num = 2; inner_st_num = 0; } else if ( ignore_stations[0] == 0 || ignore_stations[1] == 0 ) { outer_st_num = 3; mid_st_num = 2; inner_st_num = 1; } } else if ( ignore_stations[0] == 3 || ignore_stations[1] == 3 ) {// 1 of ignore stats is 3 if ( ignore_stations[0] == 2 || ignore_stations[1] == 2 ) { outer_st_num = 4; mid_st_num = 1; inner_st_num = 0; } else if ( ignore_stations[0] == 1 || ignore_stations[1] == 1 ) { outer_st_num = 4; mid_st_num = 2; inner_st_num = 0; } else if ( ignore_stations[0] == 0 || ignore_stations[1] == 0 ) { outer_st_num = 4; mid_st_num = 2; inner_st_num = 1; } } else if ( ignore_stations[0] == 2 || ignore_stations[1] == 2 ) {// 1 of ignore stats is 2 if ( ignore_stations[0] == 1 || ignore_stations[1] == 1 ) { outer_st_num = 4; mid_st_num = 3; inner_st_num = 0; } else if ( ignore_stations[0] == 0 || ignore_stations[1] == 0 ) { outer_st_num = 4; mid_st_num = 3; inner_st_num = 1; } } else if ( ignore_stations[0] == 1 || ignore_stations[1] == 1 ) {// 1 of ignore stats is 1 if ( ignore_stations[0] == 0 || ignore_stations[1] == 0 ) { outer_st_num = 4; mid_st_num = 3; inner_st_num = 2; } } } else { if (debug > 0) std::cout << "Error: Invalid ignore station argument." << std::endl; return false; } return true; } // ~set_seed_stations(...) void PatternRecognition::sort_by_station(const std::vector &spnts, SpacePoint2dPArray &spnts_by_station) { for ( int st_num = 0; st_num < static_cast(spnts_by_station.size()); ++st_num ) { for ( int i = 0; i < static_cast(spnts.size()); ++i ) { if ( spnts[i]->get_station() == st_num + 1 ) { spnts_by_station[st_num].push_back(spnts[i]); } } } } // ~sort_by_station(...) SpacePoint2dPArray PatternRecognition::sort_by_tracker( const std::vector &spnts) { SpacePoint2dPArray spnts_by_tracker(_n_trackers); for ( int trker_no = 0; trker_no < _n_trackers; ++trker_no ) { for ( unsigned int i = 0; i < spnts.size(); ++i ) { if ( spnts[i]->get_tracker() == trker_no ) { spnts_by_tracker[trker_no].push_back(spnts[i]); } } } return spnts_by_tracker; } int PatternRecognition::num_stations_with_unused_spnts( const SpacePoint2dPArray &spnts_by_station) { int stations_hit = 0; for ( int i = 0; i < static_cast(spnts_by_station.size()); ++i ) { int unused_sp = 0; for ( int j = 0; j < static_cast(spnts_by_station[i].size()); ++j ) { if ( !spnts_by_station[i][j]->get_used() ) { ++unused_sp; } } if ( unused_sp > 0 ) { ++stations_hit; } } return stations_hit; } // ~num_stations_with_unused_spnts(...) void PatternRecognition::stations_with_unused_spnts(const SpacePoint2dPArray &spnts_by_station, std::vector &stations_hit, std::vector &stations_not_hit) { stations_hit.clear(); stations_not_hit.clear(); for ( int i = 0; i < static_cast(spnts_by_station.size()); ++i ) { int unused_sp = 0; for ( int j = 0; j < static_cast(spnts_by_station[i].size()); ++j ) { if ( !spnts_by_station[i][j]->get_used() ) { ++unused_sp; } } if ( unused_sp > 0 ) { stations_hit.push_back(i); } else if ( unused_sp == 0 ) { stations_not_hit.push_back(i); } } } // ~stations_with_unused_spnts(...) bool PatternRecognition::set_ignore_stations(const std::vector &ignore_stations, int &ignore_st_1, int &ignore_st_2) { ignore_st_1 = -1, ignore_st_2 = -1; if ( ignore_stations.size() == 0 ) { // Leave ignore stations as -1 } else if ( ignore_stations.size() == 1 ) { ignore_st_1 = ignore_stations[0]; } else if ( ignore_stations.size() == 2 ) { ignore_st_1 = ignore_stations[0]; ignore_st_2 = ignore_stations[1]; } else { std::cerr << "Error: Invalid ignore station argument." << std::endl; return false; } return true; } // ~set_ignore_stations(...) void PatternRecognition::draw_line(const SciFiSpacePoint *sp1, const SciFiSpacePoint *sp2, SimpleLine &line_x, SimpleLine &line_y) { ThreeVector pos_outer = sp1->get_position(); ThreeVector pos_inner = sp2->get_position(); line_x.set_m(( pos_inner.x() - pos_outer.x()) / (pos_inner.z() - pos_outer.z() )); line_x.set_c(pos_outer.x() - ( pos_outer.z() * line_x.get_m()) ); line_y.set_m(( pos_inner.y() - pos_outer.y()) / (pos_inner.z() - pos_outer.z() )); line_y.set_c(pos_outer.y() - ( pos_outer.z() * line_y.get_m() )); } // ~draw_line(...) void PatternRecognition::calc_residual(const SciFiSpacePoint *sp, const SimpleLine &line_x, const SimpleLine &line_y, double &dx, double &dy) { ThreeVector pos = sp->get_position(); dx = pos.x() - ( line_x.get_c() + ( pos.z() * line_x.get_m() ) ); dy = pos.y() - ( line_y.get_c() + ( pos.z() * line_y.get_m() ) ); } // ~calc_residual(...) } // ~namespace MAUS