Main Page   Modules   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

TMuiRoadFinder.cxx

Go to the documentation of this file.
00001 #include<TMuiRoadFinder.h>
00002 #include<TMuiChannelId.hh>
00003 #include<PHGeometry.h>
00004 #include<gsl/gsl_fit.h>
00005 #include<boost/array.hpp>
00006 #include<cmath>
00007 #include<TROOT.h>
00008 #include<TMuiClusterMapO.h>
00009 #include<TMuiHitMapO.h>
00010 #include<TMuiMCHitMapO.h>
00011 
00012 // Static data members TMuiRoadFinder
00013 //
00014 bool TMuiRoadFinder::_verbose = false;
00015 bool TMuiRoadFinder::_reverse_algo = false;
00016 // cuts for whether roads should be accepted
00017 UShort_t TMuiRoadFinder::_min_cluster = 4;
00018 UShort_t TMuiRoadFinder::_min_point = 2;
00019 // cut for whether duplicate roads should be eliminated
00020 UShort_t TMuiRoadFinder::_max_cluster_share = 4;
00021 // evaluation stuff
00022 bool TMuiRoadFinder::_evaluation = false; 
00023 TNtuple* TMuiRoadFinder::_ntuple = 0; 
00024 TFile* TMuiRoadFinder::_file = 0; 
00025     
00026 // Static data members TMuiRoadFinder::Road
00027 //
00028 bool TMuiRoadFinder::Road::_verbose = false;
00029 // "tube" cuts for whether new clusters should be added to road
00030 double TMuiRoadFinder::Road::_dca_cut = 4.0;  
00031 double TMuiRoadFinder::Road::_prox_cut = 4.0;
00032 // different orientations have different z values (offset = 2.0 cm)
00033 // i.e. intersections in x-y from lines are still somewhat distant
00034 double TMuiRoadFinder::Road::_orient_z_dist = 2.0;
00035 double TMuiRoadFinder::Road::_tube_width = 8.35; // cm
00036 // evaluation stuff
00037 bool TMuiRoadFinder::Road::_evaluation = false; 
00038 bool TMuiRoadFinder::Road::_use_slope_cuts = false; 
00039 TFile* TMuiRoadFinder::Road::_file = 0; 
00040 TNtuple* TMuiRoadFinder::Road::_ntuple = 0; 
00041 boost::array<float,20> TMuiRoadFinder::Road::_eval_data;
00042 
00043 // TMuiRoadFinder methods
00044 // 
00045 // Find all roads -- Windows are wide open
00046 //
00047 void
00048 TMuiRoadFinder::find(TMuiClusterMapO* cluster_map)
00049 {
00050   // Never trust a raw pointer
00051   //
00052   if(!cluster_map) throw std::logic_error(DESCRIPTION("TMuiClusterMapO pointer is null"));
00053 
00054   for(int arm=0; arm<MUIOO::NumberOfArms;++arm){
00055     find(cluster_map, arm);
00056   }  
00057 }
00058 
00059 // Find Road in specified arm in given window
00060 //
00061 void
00062 TMuiRoadFinder::find(TMuiClusterMapO* cluster_map,
00063                      UShort_t arm,
00064                      bool use_window,
00065                      const road_window& theta_window,
00066                      const road_window& phi_window) 
00067 {
00068   if(_verbose) {
00069     std::cout << " TMuiRoadFinder::find: location: " << " arm: " << arm << std::endl;
00070   }
00071   // Never trust a raw pointer
00072   //
00073   if(!cluster_map) throw std::logic_error(DESCRIPTION("TMuiClusterMapO pointer is null"));  
00074 
00075   // Local storage for cluster list 
00076   //
00077   typedef std::list<TMuiClusterMapO::value_type> local_list_type;
00078   local_list_type local_list;
00079 
00080   // Store all clusters in this arm in local list. 
00081   //
00082   TMuiClusterMapO::iterator cluster_iter = cluster_map->get(arm);
00083   while(TMuiClusterMapO::pointer cluster_ptr = cluster_iter.next()){
00084     local_list.push_back(*cluster_ptr);
00085   }
00086 
00087   // Run the algorithm 
00088   //
00089   local_list_type::iterator iter = local_list.begin();
00090   for(;iter!=local_list.end();++iter){
00091     // Attempt to append cluster to existing road.  If unsuccessful create new road.
00092     //
00093     bool was_appended = append_to_road(&(*iter));
00094     if(!was_appended){
00095       start_new_road(&(*iter), use_window, theta_window, phi_window);
00096     } 
00097     if(_verbose) print_roads();
00098   }
00099 
00100   // Before running the reverse algorithm we tag the roads as complete.
00101   // (this is so we don't try to add clusters previously found roads)
00102   //
00103   set_complete_tag();
00104 
00105   // Removes roads that are subsets of other roads
00106   //
00107   remove_includes();
00108 
00109   // If not in REVERSE mode punt before running reverse algorithm
00110   //
00111   if(!_reverse_algo) return;
00112   
00113   // Reverse the list
00114   //
00115   local_list.reverse();
00116 
00117   // Run the algorithm again (on the reverse sorted list)
00118   //
00119   iter = local_list.begin();
00120   for(;iter!=local_list.end();++iter){
00121     // Attempt to append cluster to existing road.  If unsuccessful create new road.
00122     //
00123     bool was_appended = append_to_road(&(*iter));
00124     if(!was_appended){
00125       start_new_road(&(*iter), use_window, theta_window, phi_window);
00126     }
00127     if(_verbose) print_roads();
00128   }
00129   
00130   // Set complete on road found in second pass
00131   //
00132   set_complete_tag();    
00133   
00134   size_t n_road = _road_list.size();
00135   _road_list.sort(road_less_ftor());
00136   _road_list.unique(road_equal_ftor());
00137   
00138   // Removes roads that are subsets of other roads
00139   //
00140   remove_includes();
00141   
00142   if(_verbose) {
00143     std::cout << " removed " << n_road - _road_list.size() << " duplicate roads" << std::endl;
00144   }
00145 }
00146 
00147 void 
00148 TMuiRoadFinder::remove_includes()
00149 {
00150   road_list::iterator iter1 = _road_list.begin();
00151   for(;iter1!=_road_list.end();++iter1){
00152     if (!iter1->get_status()) continue; // already marked for removal
00153     road_list::iterator iter2 = iter1;
00154     ++iter2;
00155     for(;iter2!=_road_list.end();++iter2){
00156       if (!iter2->get_status()) continue; // already marked for removal
00157 
00158       road_list::iterator big = (iter1->get_n_cluster() >= iter2->get_n_cluster()) ? iter1 : iter2;
00159       road_list::iterator little = (iter1->get_n_cluster() >= iter2->get_n_cluster()) ? iter2 : iter1;
00160 
00161       // Mark identical cluster includes for removal
00162       //
00163       if(std::includes(big->get_cluster_list().begin(),
00164                        big->get_cluster_list().end(),
00165                        little->get_cluster_list().begin(),
00166                        little->get_cluster_list().end())) {
00167         little->set_status(false);
00168       }      
00169 
00170       // Count the number of clusters that are shared
00171       // If it's more than _max_cluster_share, then the little road is deleted
00172       //
00173       UShort_t nshare = 0;
00174 
00175       Road::cluster_list::const_iterator big_iter = 
00176         big->get_cluster_list().begin();
00177       Road::cluster_list::const_iterator little_iter = 
00178         little->get_cluster_list().begin();
00179       for(;big_iter!=big->get_cluster_list().end();++big_iter){
00180         bool match = false;
00181         little_iter = little->get_cluster_list().begin();
00182         for(;little_iter!=little->get_cluster_list().end();++little_iter){
00183           if(big_iter->get()->get_key().get_obj_key()  
00184              == little_iter->get()->get_key().get_obj_key()) {
00185             match = true;
00186           }
00187         }
00188         if (match) nshare++;
00189       }
00190       if (nshare > _max_cluster_share) {    
00191         little->set_status(false);
00192       }
00193     }
00194   }  
00195   // Remove marked roads
00196   //
00197   _road_list.remove_if(road_bad_status_ftor());    
00198 }
00199 
00200 void
00201 TMuiRoadFinder::set_complete_tag()
00202 {
00203   road_list::iterator road_iter = _road_list.begin();
00204   road_iter = _road_list.begin();
00205   for(;road_iter!=_road_list.end();++road_iter) {
00206     if(road_iter->get_cluster_list().size() < _min_cluster ||
00207        road_iter->get_point_list().size() < _min_point) {
00208       road_iter->set_status(false);
00209     } else {
00210       road_iter->set_complete(true);
00211     }
00212   }
00213   _road_list.remove_if(road_bad_status_ftor());    
00214 }
00215 
00216 bool 
00217 TMuiRoadFinder::append_to_road(TMuiClusterMapO::pointer cluster_ptr)
00218 {    
00219   // Initialize was_appended = false
00220   // Loop over Roads in road list [
00221   //   if add_new_cluster successfull [
00222   //     set was_appended = true
00223   //   ]
00224   // ]  
00225   // return was_appended  
00226   //
00227   bool sticky_appended = false;
00228   road_list::iterator road_iter = _road_list.begin();
00229   for(;road_iter!=_road_list.end();++road_iter){
00230     
00231     // Punt if this road has the complete flag set
00232     //
00233     if(road_iter->is_complete()) continue;
00234     
00235     // Attempt to append cluster to current road
00236     //
00237     bool was_appended =  road_iter->add_cluster(cluster_ptr);
00238     sticky_appended = (sticky_appended) ? sticky_appended : was_appended;    
00239   }
00240   return sticky_appended;
00241 }
00242 
00243 void
00244 TMuiRoadFinder::print_roads() const
00245 {
00246   MUIOO::PRINT(std::cout,"**");
00247   std::for_each(_road_list.begin(), _road_list.end(), road_print_ftor());
00248   MUIOO::PRINT(std::cout,"**");
00249 }
00250 
00251 void
00252 TMuiRoadFinder::abort_new_road()
00253 {
00254   _road_list.pop_front();                           
00255 }
00256 
00257 TMuiRoadFinder::Road*
00258 TMuiRoadFinder::start_new_road(TMuiClusterMapO::pointer cluster_ptr,
00259                                bool use_window,
00260                                const road_window& theta_window,
00261                                const road_window& phi_window)
00262 {
00263   _road_list.push_front(Road(this, cluster_ptr, use_window,
00264                              theta_window, phi_window));                            
00265 
00266   // Return a pointer to the newly created Road
00267   //
00268   return &(*_road_list.begin());
00269 }
00270 
00271 
00272 // TMuiRoadFinder::Road methods
00273 //
00274 bool 
00275 TMuiRoadFinder::Road::add_cluster(TMuiClusterMapO::pointer cluster_ptr) 
00276 {
00277   bool was_added=false;
00278   if(_evaluation) _eval_data.assign(0);
00279 
00280   // If road has a cluster in this plane and orientation and has a least 2 clusters 
00281   // already then call bifurcate
00282   //
00283   if(!unique_check(cluster_ptr)) {
00284     if(_clusters.size()>1) {
00285       was_added = bifurcate(cluster_ptr);
00286       return was_added;
00287     } else {
00288       return false; // too small to add to
00289     }
00290   } 
00291   
00292   // If we made it until here, it means that this cluster is the first in this plane 
00293   // and orientation and could add to our information on the road (if it fits in)
00294 
00295   // if Road has point [
00296   //  project point to z of cluster
00297   //  test theta, phi window of projected point
00298   //  test projected point - cluster DCA
00299   //  if added update road parameters
00300   // ] else [ 
00301   //  if can make point with this cluster [
00302   //    test theta, phi window of point
00303   //    if added update road parameters
00304   //  ] else [
00305   //    test proximity of cluster with existing cluster
00306   //  ]
00307   // ]  
00308   
00309   if(_points.size() != 0){
00310 
00311     PHPoint point = project(cluster_ptr->get()->get_centroidpos().getZ());
00312     if(test_window(point) && 
00313        check_dca(cluster_ptr,point) &&
00314        check_proximity(cluster_ptr)){
00315       update_road(cluster_ptr);
00316       was_added = true;
00317     }
00318     
00319   } 
00320   else {
00321     // Check if this cluster is parallel to existing cluster
00322     //
00323     if(!check_parallel(cluster_ptr)) {
00324       // Not parallel (and the right panel/plane) so it will intersect
00325       // with an existing cluster in this road - update&add
00326       if (has_window()) {
00327         PHPoint point = make_point(cluster_ptr);
00328         // If point is in window then add coord and point to stub
00329         //
00330         if(test_window(point)){
00331           update_road(cluster_ptr);
00332           was_added = true;
00333         }
00334       }
00335       else {
00336         update_road(cluster_ptr);
00337         was_added = true;
00338       } 
00339     }
00340     else {
00341       // Prior and current cluster are parallel, check proximity and add
00342       // cluster to road if proximity cut is satisfied.
00343       //
00344       if (check_proximity(cluster_ptr)) {
00345         update_road(cluster_ptr);
00346         was_added = true;
00347       }
00348     }
00349   }  
00350 
00351   if(_clusters.size() >= 3){
00352     check_slope();
00353   }
00354   if(_evaluation) {
00355     _eval_data[0] = _arm;
00356     _eval_data[1] = cluster_ptr->get()->get_plane();
00357     _eval_data[2] = cluster_ptr->get()->get_panel();
00358     _eval_data[3] = cluster_ptr->get()->get_orientation();
00359     _eval_data[4] = _clusters.size(); 
00360     _eval_data[5] = was_added ? 1 : 0; 
00361     _ntuple->Fill(&(_eval_data[0]));
00362   }
00363   return was_added;
00364 }
00365  
00366 bool 
00367 TMuiRoadFinder::Road::check_parallel(const TMuiClusterMapO::pointer cluster_ptr) const 
00368 {  
00369   // Loop over clusters in road cluster list and check for non-parallel cluster
00370   // in the same plane, panel
00371   cluster_list::const_iterator cluster_iter = _clusters.begin();
00372   for(;cluster_iter!=_clusters.end();++cluster_iter){
00373     if ( (cluster_iter->get()->get_plane() == cluster_ptr->get()->get_plane()) && 
00374          (cluster_iter->get()->get_panel() == cluster_ptr->get()->get_panel()) && 
00375          (cluster_iter->get()->get_orientation() != cluster_ptr->get()->get_orientation()) ) {
00376       return false;
00377     }
00378   }
00379   return true;
00380 }
00381 
00382 bool
00383 TMuiRoadFinder::Road::check_slope() const
00384 {
00385   return true;
00386 }
00387 
00388 bool 
00389 TMuiRoadFinder::Road::test_window(const PHPoint& point) const
00390 {
00391   // If there is no window defined for this road then  
00392   // we can say that the new cluster falls within the window..
00393   //
00394   if (!has_window()) {
00395     return true;
00396   }
00397   
00398   // If we haven't got any points, we don't have a well-defined/centered
00399   // window yet
00400   //
00401   if (_points.size() == 0) {
00402     return true;
00403   }
00404 
00405   TMuiRoadFinder::WindowEnum phi_check = 
00406     TMuiRoadFinder::check_phi_window(point,_phi_window);
00407 
00408   TMuiRoadFinder::WindowEnum theta_check = 
00409     TMuiRoadFinder::check_theta_window(point,_theta_window);
00410 
00411   if(_evaluation) {
00412     _eval_data[6] = phi_check; 
00413     _eval_data[7] = theta_check; 
00414     _eval_data[10] = point.getX(); 
00415     _eval_data[11] = point.getY();
00416     _eval_data[12] = point.getZ();  
00417     _eval_data[13] = _phi_window.first;  
00418     _eval_data[14] = _phi_window.second;  
00419     _eval_data[15] = _theta_window.first;  
00420     _eval_data[16] = _theta_window.second;  
00421   }
00422 
00423   if(phi_check == TMuiRoadFinder::IN_WINDOW && 
00424      theta_check == TMuiRoadFinder::IN_WINDOW) {
00425     return true;
00426   } 
00427   else {
00428     return false;
00429   }
00430 }
00431 
00432 bool 
00433 TMuiRoadFinder::Road::check_dca(const TMuiClusterMapO::pointer cluster_ptr, 
00434                                 const PHPoint& point)  const 
00435 {
00436   // get the line info for the cluster
00437   PHLine line = cluster_ptr->get()->get_coord();
00438   double distance = PHGeometry::distanceLinePoint(line, point);
00439   // normalize distance to something 
00440   // width is from the narrow dimension of the tube
00441   if (_tube_width > 0) distance /= _tube_width; 
00442   else return false;
00443        
00444   if(_evaluation) {
00445     _eval_data[8] = distance; 
00446   }
00447  
00448   if(distance < _dca_cut) {
00449     // since the line distance calculation assumes an infinite line, 
00450     // it is possible to get an acceptable distance even when the line is
00451     // offset from the point. Use centroidpos, which should not be more
00452     // than half the length away from any point, for this
00453     double projdist = PHGeometry::distancePointToPoint(cluster_ptr->get()->get_centroidpos(), point);
00454     double halflength = 0.5*line.length();
00455     if (projdist < halflength) {
00456       return true;
00457     }
00458   }
00459   return false;
00460 }
00461 
00462 bool
00463 TMuiRoadFinder::Road::bifurcate(TMuiClusterMapO::pointer cluster_ptr)  
00464 {
00465   // Sanity check
00466   //
00467   if(_finder->_road_list.size() > 500) {
00468     throw std::runtime_error(DESCRIPTION("bifurcate: too many roads"));
00469   }
00470 
00471   // New road pointer with null initialization
00472   //
00473   TMuiRoadFinder::Road* new_road_ptr = 0;
00474   
00475   // Loop over cluster list; copy clusters from old road that are not in the 
00476   // same plane as cluster_ptr
00477   //
00478   cluster_list::iterator cluster_iter = _clusters.begin();
00479   for(;cluster_iter!=_clusters.end();++cluster_iter){
00480     if(cluster_ptr->get()->get_plane() != cluster_iter->get()->get_plane()) {      
00481       // Old cluster
00482       //
00483       TMuiClusterMapO::value_type old_cluster = *cluster_iter;
00484 
00485       // First time start the new road -- subsequent times update road with old cluster
00486       //
00487       if(!new_road_ptr) {
00488         new_road_ptr = _finder->start_new_road(&old_cluster, _has_window, _theta_window, _phi_window);
00489       } else {
00490         new_road_ptr->update_road(&old_cluster);
00491       }
00492     }
00493   }
00494 
00495   // If cluster_ptr is the first then return here
00496   //
00497   if(!new_road_ptr) {
00498     _finder->start_new_road(cluster_ptr, _has_window, _theta_window, _phi_window);
00499     return true;
00500   }
00501   
00502   // Now we have a road that is guarenteed *not* to have a cluster in the same plane
00503   // as cluster_ptr.  Here we invoke a fancy (obtuse) piece of recursion by calling
00504   // add_cluster using the new road pointer. This will ensure that exactly the same
00505   // criteria is applied for adding clusters to roads in both the original and
00506   // new (bifurcated) road.
00507   //
00508   bool was_added = new_road_ptr->add_cluster(cluster_ptr);
00509   if(was_added) {
00510     return true;
00511   } else {
00512     _finder->abort_new_road();
00513     return false;
00514   }
00515 }
00516 
00517 
00518 bool 
00519 TMuiRoadFinder::Road::check_proximity(TMuiClusterMapO::pointer cluster_ptr) const 
00520 {
00521   // This method is called only when we don't have any points found yet, and
00522   // not any non-parallell clusters to this new one, in the same plane and panel.
00523   // If the new one is close enough, we'll add it to our cluster list.
00524   //
00525   // Idiot check
00526   //
00527   if(!_clusters.size()) throw std::logic_error(DESCRIPTION("attempted comparison with null entry"));
00528 
00529   PHPoint point1 = cluster_ptr->get()->get_centroidpos();
00530 
00531   // Loop over clusters in road cluster list and get the closest (in Z) parallel cluster
00532   double distance = DBL_MAX;
00533   cluster_list::const_iterator best_iter;
00534   cluster_list::const_iterator cluster_iter = _clusters.begin();
00535   for(;cluster_iter!=_clusters.end();++cluster_iter){
00536     if (cluster_iter->get()->get_orientation() == cluster_ptr->get()->get_orientation()) {
00537       PHPoint point2 = cluster_iter->get()->get_centroidpos();
00538       double thisdistance = std::fabs(point2.getZ() - point1.getZ());
00539       if (thisdistance < distance) {
00540         distance = thisdistance;
00541         best_iter = cluster_iter;
00542       }
00543     }
00544   }
00545 
00546   if (distance == DBL_MAX) { 
00547     // nothing found to compare with
00548     return false;
00549   }
00550 
00551   PHPoint point2 = best_iter->get()->get_centroidpos();
00552   point1.setZ(0);
00553   point2.setZ(0);
00554   distance = PHGeometry::distancePointToPoint(point1,point2);
00555 
00556   if (_tube_width > 0) distance /= _tube_width; 
00557   else return false;
00558 
00559   if(_evaluation) {
00560     _eval_data[9] = distance; 
00561   }
00562 
00563   if(distance < _prox_cut) {
00564     return true;
00565   }
00566   return false;
00567 }
00568 
00569 void
00570 TMuiRoadFinder::Road::update_road(TMuiClusterMapO::pointer cluster_ptr) 
00571 {
00572   // Push cluster onto cluster list
00573   //
00574   _clusters.insert(*cluster_ptr);
00575   
00576   // Regenerate points list with new cluster -- repetitive but
00577   // makes the code simple.
00578   //
00579   _points.clear();
00580 
00581   // Loop over all unique combinations of clusters in this road,
00582   // attempt to make points out of cluster that share a common
00583   // plane.
00584   cluster_list::const_iterator iter1 = _clusters.begin();
00585   for(;iter1!=_clusters.end();++iter1){
00586 
00587     PHLine line1 = iter1->get()->get_coord();
00588     cluster_list::const_iterator iter2 = iter1;
00589     ++iter2;
00590     
00591     for(;iter2!=_clusters.end();++iter2){
00592      
00593       if(iter1->get()->get_plane() == iter2->get()->get_plane() &&
00594          iter1->get()->get_panel() == iter2->get()->get_panel() &&
00595          iter1->get()->get_orientation() != iter2->get()->get_orientation() ){
00596 
00597         PHLine line2 = iter2->get()->get_coord();
00598 
00599         // check possible intersection of line1 and line2
00600         double distance = PHGeometry::distanceLineLine(line1, line2);
00601         
00602         if (distance <= _orient_z_dist) // we had an intersection
00603           {
00604             PHPoint point = PHGeometry::closestApproachLineLine(line1, line2);
00605             _points.push_back(point);
00606           }
00607       }
00608     }
00609   }
00610 
00611   // update fit parameters
00612   //  std::cout << " number of points " << _points.size() << endl;
00613   if(_points.size()==0){
00614 
00615     // If we have 0 points then just initialize the fit_par with the 
00616     // center of the first cluster
00617     //
00618     iter1 = _clusters.begin();
00619     PHPoint mid_point = iter1->get()->get_centroidpos();
00620     // One point, take the point with 0 angles (dx/ydz)
00621     //
00622     _fit_par.set_x(mid_point.getX());
00623     _fit_par.set_y(mid_point.getY());
00624     _fit_par.set_z(mid_point.getZ());
00625     _fit_par.set_dxdz(0);
00626     _fit_par.set_dydz(0);    
00627   } 
00628   else if(_points.size()==1){
00629     
00630     // One point, take the point with 0 angles (dx/ydz)
00631     //
00632     _fit_par.set_x(_points.begin()->getX());
00633     _fit_par.set_y(_points.begin()->getY());
00634     _fit_par.set_z(_points.begin()->getZ());
00635     _fit_par.set_dxdz(0);
00636     _fit_par.set_dydz(0);
00637 
00638     // center the phi/theta windows around the found point
00639     PHSphPoint spherepoint;
00640     PHGeometry::cartesianToSpherical(_points[0], spherepoint);
00641     double half_phi_window_size = 0.5*(_phi_window.second - _phi_window.first);
00642     double half_theta_window_size = 0.5*(_theta_window.second - _theta_window.first);
00643 
00644     _phi_window.first = static_cast<double>(spherepoint.getPhi())
00645       - half_phi_window_size; 
00646     _phi_window.second = static_cast<double>(spherepoint.getPhi())
00647       + half_phi_window_size; 
00648     _theta_window.first = static_cast<double>(spherepoint.getTheta())
00649       - half_theta_window_size;  
00650     _theta_window.second = static_cast<double>(spherepoint.getTheta())
00651       + half_theta_window_size; 
00652   } 
00653   else if(_points.size()>1) {
00654 
00655     // More than one point, do a linear fit
00656     //
00657     // The second argument is the array dimension
00658     boost::array<double,MUIOO::MAX_PLANE> x = {{0}}; 
00659     boost::array<double,MUIOO::MAX_PLANE> y = {{0}}; 
00660     boost::array<double,MUIOO::MAX_PLANE> z = {{0}}; 
00661       
00662     double z0 = _points[0].getZ();
00663     size_t n_data = _points.size();
00664 
00665     // use constants from float.h to really init min/max properly
00666     double z_max = -DBL_MAX; 
00667     double z_min = DBL_MAX;
00668 
00669     PHSphPoint spherepoint;
00670     double phi_sum = 0.0;
00671     double theta_sum = 0.0;
00672     double half_phi_window_size = 0.5*(_phi_window.second - _phi_window.first);
00673     double half_theta_window_size = 0.5*(_theta_window.second - _theta_window.first);
00674 
00675     for(size_t i=0;i<n_data;++i){
00676       PHGeometry::cartesianToSpherical(_points[i], spherepoint);
00677       phi_sum += spherepoint.getPhi();
00678       theta_sum += spherepoint.getTheta();
00679       x.at(i) = _points[i].getX();
00680       y.at(i) = _points[i].getY();
00681       z.at(i) = _points[i].getZ() - z0;
00682       z_min = std::min(z_min,_points[i].getZ());
00683       z_max = std::max(z_max,_points[i].getZ());
00684     }
00685 
00686     phi_sum /= n_data;
00687     theta_sum /= n_data;
00688     _phi_window.first = phi_sum - half_phi_window_size; 
00689     _phi_window.second = phi_sum + half_phi_window_size; 
00690     _theta_window.first = theta_sum - half_theta_window_size;  
00691     _theta_window.second = theta_sum + half_theta_window_size;  
00692 
00693     double x0=0,m_x=0, y0=0, m_y=0;
00694     double cov00=0, cov11=0, cov22=0,chi2x=0,chi2y=0;
00695       
00696     // Fit x: method from gsl_fit.h
00697     //
00698     gsl_fit_linear(z.begin(),1,x.begin(),1,n_data,
00699                    &x0,&m_x,&cov00,&cov11,&cov22,&chi2x);
00700       
00701     // Fit y
00702     //
00703     gsl_fit_linear(z.begin(),1,y.begin(),1,n_data,
00704                    &y0,&m_y,&cov00,&cov11,&cov22,&chi2y);
00705 
00706     // Sanity check (dx/dz dy/dz cut)
00707     //
00708     if(std::fabs(m_x) > 10 || std::fabs(m_y) > 10) {
00709       _status = false;
00710       return;
00711     }
00712 
00713     _fit_par.set_x(x0);
00714     _fit_par.set_y(y0);
00715     _fit_par.set_z(z0);
00716     _fit_par.set_dxdz(m_x);
00717     _fit_par.set_dydz(m_y);
00718     
00719     // "begin" is closest to interaction region
00720     //
00721     if(_arm == MUIOO::South) {
00722       _fit_par.set_z_begin(z_max) ;
00723       _fit_par.set_z_end(z_min);
00724     } else {
00725       _fit_par.set_z_begin(z_min) ;
00726       _fit_par.set_z_end(z_max);
00727     }
00728   }
00729 }
00730 
00731 PHPoint
00732 TMuiRoadFinder::Road::project(double z) const 
00733 {
00734   return TMutTrackUtil::linear_track_model(&_fit_par,z);
00735 }
00736 
00737 PHPoint
00738 TMuiRoadFinder::Road::make_point(const TMuiClusterMapO::pointer cluster_ptr) const 
00739 {  
00740   // get the line info for the cluster
00741   PHLine line1 = cluster_ptr->get()->get_coord();
00742   // Loop over clusters in road cluster list and check for non-parallel cluster
00743   // in the same plane, panel
00744   cluster_list::const_iterator cluster_iter = _clusters.begin();
00745   for(;cluster_iter!=_clusters.end();++cluster_iter){
00746     if ( (cluster_iter->get()->get_plane() == cluster_ptr->get()->get_plane()) && 
00747          (cluster_iter->get()->get_panel() == cluster_ptr->get()->get_panel()) && 
00748          (cluster_iter->get()->get_orientation() != cluster_ptr->get()->get_orientation()) ) { 
00749       // there should only be one candidate in the list, so we should have it now
00750       PHLine line2 = cluster_iter->get()->get_coord();
00751       // check possible intersection of line1 and line2
00752       double distance = PHGeometry::distanceLineLine(line1, line2);
00753         
00754       if (distance <= _orient_z_dist) // we had an intersection
00755         {
00756           PHPoint point = PHGeometry::closestApproachLineLine(line1, line2);
00757           return point;
00758         }
00759     }
00760   }
00761   return PHPoint();
00762 }
00763 
00764 bool
00765 TMuiRoadFinder::Road::unique_check(TMuiClusterMapO::pointer cluster_ptr) const
00766 {
00767   // Loop over clusters and punt if the road already has a cluster in
00768   // this plane and orientation. (no panel check here)
00769   //
00770   cluster_list::const_iterator cluster_iter = _clusters.begin();
00771   for(;cluster_iter!=_clusters.end();++cluster_iter){
00772     
00773    if(cluster_ptr->get()->get_plane() == cluster_iter->get()->get_plane() &&
00774       cluster_ptr->get()->get_orientation() == cluster_iter->get()->get_orientation()) {
00775      return false;
00776    }
00777   }
00778   return true;
00779 }
00780 
00781 bool
00782 TMuiRoadFinder::Road::check_theta_window(const TMuiRoadFinder::road_window& theta_window) const 
00783 {
00784   double theta = get_theta();
00785   return (theta > theta_window.first && theta < theta_window.second);
00786 }
00787 
00788 bool
00789 TMuiRoadFinder::Road::check_phi_window(const TMuiRoadFinder::road_window& phi_window) const 
00790 {
00791   // Project onto x and y axis to avoid [0,2PI] boundary shenanigans
00792   //
00793   double x1 = std::cos(phi_window.first);
00794   double x2 = std::cos(phi_window.second);
00795   double y1 = std::sin(phi_window.first);
00796   double y2 = std::sin(phi_window.second);
00797   double xp = std::cos(get_phi());
00798   double yp = std::sin(get_phi());
00799 
00800   double r1 = std::sqrt(MUIOO::SQUARE(x1) + MUIOO::SQUARE(y1));
00801   double r2 = std::sqrt(MUIOO::SQUARE(x2) + MUIOO::SQUARE(y2));
00802   double rp = std::sqrt(MUIOO::SQUARE(xp) + MUIOO::SQUARE(yp));
00803   
00804   double dphi_window = std::acos((x1*x2 + y1*y2)/(r1*r2));
00805   double dphi_left = std::acos((x1*xp + y1*yp)/(r1*rp));
00806   double dphi_right = std::acos((x2*xp + y2*yp)/(r2*rp));
00807   
00808   // intermediate value -- has to be within dphi_window of
00809   // both edges.
00810   //
00811   return (dphi_left < dphi_window && dphi_right < dphi_window);
00812 }
00813 
00814 void 
00815 TMuiRoadFinder::Road::initialize_evaluation()
00816 { 
00817   if(_evaluation) return;
00818 
00819   _file = (TFile*)gROOT->GetListOfFiles()->FindObject("muioo_eval_ntuple.root");
00820   if (_file) {
00821     MUIOO::TRACE("TMuiRoadFinder::Road::initialize_evaluation, creating eval root file");
00822     _file = new TFile("muioo_eval_ntuple.root", "RECREATE");
00823   }
00824 
00825   // Fields for stub finder algorithm during add cluster stage
00826   //
00827   _ntuple = new TNtuple("road_cluster","road_cluster","arm:plane:panel:orientation:ncoord:added:phi_check:theta_check:dca_dist:prox_dist:x:y:z:phi1:phi2:theta1:theta2");
00828   cout << " TMuiRoadFinder::Road::initialize_evaluation() ntuple created" << endl; 
00829   
00830   _evaluation = true;
00831   
00832   return;
00833 }
00834 void 
00835 TMuiRoadFinder::Road::finish_evaluation()
00836 {  
00837   if(_ntuple) delete _ntuple;
00838   _evaluation = false;
00839 }
00840 
00841 
00842 std::list<TMuiClusterMapO::value_type>
00843 TMuiRoadFinder::get_coords_in_window(TMuiClusterMapO* cluster_map,
00844                                      UShort_t arm,
00845                                      const road_window& theta_window,
00846                                      const road_window& phi_window)
00847 {
00848   // Local storage for coordinate list 
00849   //
00850   typedef std::list<TMuiClusterMapO::value_type> local_list_type;
00851   local_list_type local_list;
00852   
00853   TMuiClusterMapO::iterator cluster_iter = cluster_map->get(arm);
00854 
00855   while(TMuiClusterMapO::pointer cluster_ptr = cluster_iter.next()){
00856 
00857     WindowEnum phi_begin = 
00858       check_phi_window(cluster_ptr->get()->get_coord_begin(), phi_window);
00859     WindowEnum phi_end = 
00860       check_phi_window(cluster_ptr->get()->get_coord_end(), phi_window);
00861 
00862     // Either the invervals overlap or the coord phi interval spans 
00863     // the phi window.  
00864     //
00865     bool in_phi_window = false;
00866     if((phi_begin == IN_WINDOW || phi_end == IN_WINDOW) ||
00867        (phi_begin == HIGH_WINDOW && phi_end == LOW_WINDOW) ||
00868        (phi_begin == LOW_WINDOW && phi_end == HIGH_WINDOW)) {
00869       in_phi_window = true;
00870     }
00871     
00872     WindowEnum theta_begin = 
00873       check_theta_window(cluster_ptr->get()->get_coord_begin(), theta_window);
00874     WindowEnum theta_end = 
00875       check_theta_window(cluster_ptr->get()->get_coord_end(), theta_window);
00876 
00877     // Either the invervals overlap or the coord theta interval spans 
00878     // the theta window.  
00879     //
00880     bool in_theta_window = false;
00881     if((theta_begin == IN_WINDOW || theta_end == IN_WINDOW) ||
00882        (theta_begin == HIGH_WINDOW && theta_end == LOW_WINDOW) ||
00883        (theta_begin == LOW_WINDOW && theta_end == HIGH_WINDOW)) {
00884       in_theta_window = true;    
00885     }
00886 
00887     if(in_theta_window && in_phi_window) local_list.push_back(*cluster_ptr);
00888   }    
00889   return local_list;
00890 }
00891 
00892 
00893 TMuiRoadFinder::WindowEnum
00894 TMuiRoadFinder::check_phi_window(const PHPoint& point, 
00895                                  const TMuiRoadFinder::road_window&phi_window) 
00896 {
00897   // Convert to spherical coordinates
00898   PHSphPoint spherepoint;
00899   PHGeometry::cartesianToSpherical(point, spherepoint);
00900  
00901   // spherepoints phi-coordinate should be in the range between
00902   // the first and second phi-window values.
00903   double thisphi = spherepoint.getPhi();
00904   double dphi_right = phi_window.second - thisphi;
00905   double dphi_left = thisphi - phi_window.first;
00906   // i.e. if both dphi_left/right values are positive, we are within the window
00907 
00908   // Some care need to be taken around 2PI
00909   // If the higher limit is above 2PI, and the point is on the positive side
00910   // we subtract 2PI, so the 
00911   // same scale is used as for PHSphPoint
00912   // The lower value is always less than 2PI
00913   if (phi_window.second > 2*M_PI && point.getY() > 0) {
00914     dphi_right -= 2*M_PI;
00915   }
00916 
00917   //
00918   // 1) within delta window of both indicates inside
00919   // 2) within delta of left but not right indicates left
00920   // 3) within delta of right but not left indicates right
00921   // 4) not within delta of either indicates left or right depending upon
00922   //    which is closer
00923   //
00924   if(dphi_left >= 0 && dphi_right >= 0){
00925     return IN_WINDOW;
00926   } else if(dphi_left < 0) {
00927     return LOW_WINDOW;
00928   } else if(dphi_right < 0) {
00929     return HIGH_WINDOW;
00930   } else {
00931     return HIGH_WINDOW; // this should never happen but makes compiler happy
00932   }
00933 }
00934 
00935 TMuiRoadFinder::WindowEnum
00936 TMuiRoadFinder::check_theta_window(const PHPoint& point, 
00937                                    const TMuiRoadFinder::road_window& 
00938                                    theta_window) 
00939 { 
00940   // Convert to spherical coordinates
00941   PHSphPoint spherepoint;
00942   PHGeometry::cartesianToSpherical(point, spherepoint);
00943   double theta_p = spherepoint.getTheta();
00944   
00945   if(theta_p >= theta_window.first && theta_p <= theta_window.second){
00946     return IN_WINDOW;
00947   } else if(theta_p < theta_window.first) {
00948     return LOW_WINDOW;
00949   } else if(theta_p > theta_window.second) {
00950     return HIGH_WINDOW;
00951   } else {
00952     return HIGH_WINDOW; // this should never happen but makes compiler happy
00953   }
00954 }
00955 
00956 void 
00957 TMuiRoadFinder::initialize_evaluation()
00958 {
00959   if(_evaluation) return;
00960 
00961   _file = (TFile*)gROOT->GetListOfFiles()->FindObject("muioo_eval_ntuple.root");
00962   if (_file) {
00963     MUIOO::TRACE("TMuiRoadFinder::initialize_evaluation, creating eval root file");
00964     _file = new TFile("muioo_eval_ntuple.root", "RECREATE");
00965   }
00966 
00967   // Fields for road evaluation after algorithm is complete
00968   //
00969   _ntuple = new TNtuple("road","road",
00970                         "arm:iroad:iclust:mc_exist:mc_found:"
00971                         "true_hit:bg_hit:th_true:phi_true:th_win:ph_win");
00972   
00973   _evaluation = true;
00974   return;
00975 }
00976 
00977 void TMuiRoadFinder::finish_evaluation()
00978 {
00979   if(_ntuple) delete _ntuple;
00980   _evaluation=false;
00981   return;
00982 }
00983 
00984 void 
00985 TMuiRoadFinder::evaluate(PHCompositeNode* top_node)
00986 {
00987   TMuiRoadFinder::road_list& road_list = get_road_list();
00988   TMuiRoadFinder::road_list::iterator road_list_iter = road_list.begin();
00989   for(;road_list_iter!=road_list.end();++road_list_iter){
00990     float ntvar[20] = {0};
00991     
00992     ntvar[0] = road_list_iter->get_arm();
00993     ntvar[1] = road_list_iter->get_cluster_list().size();
00994     
00995     typedef TMuiRoadFinder::Road::cluster_list road_cluster_list;
00996     road_cluster_list& cluster_list = road_list_iter->get_cluster_list();
00997     road_cluster_list::iterator cluster_iter = cluster_list.begin();    
00998     for(;cluster_iter!=cluster_list.end();++cluster_iter){
00999       TMuiClusterMapO::const_key_iterator clus_iter = cluster_iter->get()->get_associated<TMuiClusterO>();
01000       if(!clus_iter.at_end()){
01001         TMuiHitMapO::const_key_iterator hit_iter = clus_iter->get()->get_associated<TMuiHitO>();
01002         while(TMuiHitMapO::const_pointer hit_ptr = hit_iter.next()){
01003           TMuiMCHitMapO::const_key_iterator mc_hit_iter = hit_ptr->get()->get_associated<TMuiMCHitO>();
01004           if(!mc_hit_iter.at_end()){
01005           }
01006         }
01007       }
01008     }
01009   }
01010 }
01011 
01012 
01013 

MUIOO: PHENIX Muon Identifier Analysis Framework. Documentation by doxygen
Last modified: