|
SISCone
2.0.5
|
00001 00002 // File: vicinity.cpp // 00003 // Description: source file for particle vicinity (Cvicinity class) // 00004 // This file is part of the SISCone project. // 00005 // WARNING: this is not the main SISCone trunk but // 00006 // an adaptation to spherical coordinates // 00007 // For more details, see http://projects.hepforge.org/siscone // 00008 // // 00009 // Copyright (c) 2006-2008 Gavin Salam and Gregory Soyez // 00010 // // 00011 // This program is free software; you can redistribute it and/or modify // 00012 // it under the terms of the GNU General Public License as published by // 00013 // the Free Software Foundation; either version 2 of the License, or // 00014 // (at your option) any later version. // 00015 // // 00016 // This program is distributed in the hope that it will be useful, // 00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of // 00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // 00019 // GNU General Public License for more details. // 00020 // // 00021 // You should have received a copy of the GNU General Public License // 00022 // along with this program; if not, write to the Free Software // 00023 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // 00024 // // 00025 // $Revision:: 255 $// 00026 // $Date:: 2008-07-12 17:40:35 +0200 (Sat, 12 Jul 2008) $// 00028 00029 #include "vicinity.h" 00030 #include <math.h> 00031 #include <algorithm> 00032 #include <iostream> 00033 00034 namespace siscone_spherical{ 00035 00036 using namespace std; 00037 00038 /************************************************************* 00039 * CSphvicinity_elm implementation * 00040 * element in the vicinity of a parent. * 00041 * class used to manage one points in the vicinity * 00042 * of a parent point. * 00043 *************************************************************/ 00044 00045 // ordering pointers to CSphvicinity_elm 00046 //--------------------------------------- 00047 bool ve_less(CSphvicinity_elm *ve1, CSphvicinity_elm *ve2){ 00048 return ve1->angle < ve2->angle; 00049 } 00050 00051 00052 /************************************************************* 00053 * CSphvicinity implementation * 00054 * list of element in the vicinity of a parent. * 00055 * class used to manage the points which are in the vicinity * 00056 * of a parent point. The construction of the list can be * 00057 * made from a list of points or from a quadtree. * 00058 *************************************************************/ 00059 00060 // default constructor 00061 //--------------------- 00062 CSphvicinity::CSphvicinity(){ 00063 n_part = 0; 00064 00065 ve_list = NULL; 00066 #ifdef USE_QUADTREE_FOR_STABILITY_TEST 00067 quadtree = NULL; 00068 #endif 00069 00070 parent = NULL; 00071 VR2 = VR = 0.0; 00072 00073 } 00074 00075 // constructor with initialisation 00076 //--------------------------------- 00077 CSphvicinity::CSphvicinity(vector<CSphmomentum> &_particle_list){ 00078 parent = NULL; 00079 ve_list = NULL; 00080 #ifdef USE_QUADTREE_FOR_STABILITY_TEST 00081 quadtree = NULL; 00082 #endif 00083 cosVR = VR2 = tan2R = VR = 0.0; 00084 00085 set_particle_list(_particle_list); 00086 } 00087 00088 // default destructor 00089 //-------------------- 00090 CSphvicinity::~CSphvicinity(){ 00091 if (ve_list!=NULL) 00092 delete[] ve_list; 00093 00094 #ifdef USE_QUADTREE_FOR_STABILITY_TEST 00095 if (quadtree!=NULL) 00096 delete quadtree; 00097 #endif 00098 } 00099 00100 /* 00101 * set the particle_list 00102 * - particle_list list of particles (type CSphmomentum) 00103 * - n number of particles in the list 00104 ************************************************************/ 00105 void CSphvicinity::set_particle_list(vector<CSphmomentum> &_particle_list){ 00106 int i,j; 00107 #ifdef USE_QUADTREE_FOR_STABILITY_TEST 00108 double eta_max=0.0; 00109 #endif 00110 00111 // if the particle list is not empty, destroy it ! 00112 if (ve_list!=NULL){ 00113 delete[] ve_list; 00114 } 00115 vicinity.clear(); 00116 #ifdef USE_QUADTREE_FOR_STABILITY_TEST 00117 if (quadtree!=NULL) 00118 delete quadtree; 00119 #endif 00120 00121 // allocate memory array for particles 00122 // Note: - we compute max for |eta| 00123 // - we allocate indices to particles 00124 n_part = 0; 00125 plist.clear(); 00126 pincluded.clear(); 00127 for (i=0;i<(int) _particle_list.size();i++){ 00128 // if a particle is colinear with the beam (infinite rapidity) 00129 // we do not take it into account 00130 //if (fabs(_particle_list[i].pz)!=_particle_list[i].E){ 00131 plist.push_back(_particle_list[i]); 00132 pincluded.push_back(siscone::Cvicinity_inclusion()); // zero inclusion status 00133 00134 // the parent_index is handled in the split_merge because 00135 // of our multiple-pass procedure. 00136 // Hence, it is not required here any longer. 00137 // plist[n_part].parent_index = i; 00138 plist[n_part].index = n_part; 00139 00140 // make sure the reference is randomly created 00141 plist[n_part].ref.randomize(); 00142 00143 #ifdef USE_QUADTREE_FOR_STABILITY_TEST 00144 if (fabs(plist[n_part].eta)>eta_max) eta_max=fabs(plist[n_part].eta); 00145 #endif 00146 n_part++; 00147 //} 00148 } 00149 00150 // allocate quadtree and vicinity_elm list 00151 // note: we set phi in [-pi:pi] as it is the natural range for atan2! 00152 ve_list = new CSphvicinity_elm[2*n_part]; 00153 #ifdef USE_QUADTREE_FOR_STABILITY_TEST 00154 eta_max+=0.1; 00155 quadtree = new siscone::Cquadtree(0.0, 0.0, eta_max, M_PI); 00156 #endif 00157 00158 // append particle to the vicinity_elm list 00159 j = 0; 00160 for (i=0;i<n_part;i++){ 00161 #ifdef USE_QUADTREE_FOR_STABILITY_TEST 00162 quadtree->add(&plist[i]); 00163 #endif 00164 ve_list[j].v = ve_list[j+1].v = &plist[i]; 00165 ve_list[j].is_inside = ve_list[j+1].is_inside = &(pincluded[i]); 00166 j+=2; 00167 } 00168 00169 } 00170 00171 00172 /* 00173 * build the vicinity list from a list of points. 00174 * - _parent reference particle 00175 * - _VR vicinity radius 00176 ************************************************************/ 00177 void CSphvicinity::build(CSphmomentum *_parent, double _VR){ 00178 int i; 00179 00180 // set parent and radius 00181 parent = _parent; 00182 00183 VR = _VR; 00184 VR2 = VR*VR; 00185 cosVR = cos(VR); 00186 R2 = 0.25*VR2; 00187 R = 0.5*VR; 00188 double tmp = tan(R); 00189 tan2R = tmp*tmp; 00190 00191 D2_R = 2.0*(1-cos(R)); 00192 //tmp = sqrt(D2_R); 00193 inv_R_EPS_COCIRC = 1.0 / R / EPSILON_COCIRCULAR; 00194 inv_R_2EPS_COCIRC = 0.5 / R / EPSILON_COCIRCULAR; 00195 00196 // clear vicinity 00197 vicinity.clear(); 00198 00199 // init parent variables 00200 // we cpte the direction of the centre and two orthogonal ones 00201 // to measure the angles. Those are taken orthogonal to the 00202 // axis of smallest components (of the centre) to increase precision 00203 parent_centre = (*parent)/parent->_norm; 00204 parent_centre.get_angular_directions(angular_dir1, angular_dir2); 00205 angular_dir1 /= angular_dir1._norm; 00206 angular_dir2 /= angular_dir2._norm; 00207 00208 // really browse the particle list 00209 for (i=0;i<n_part;i++){ 00210 append_to_vicinity(&plist[i]); 00211 } 00212 00213 // sort the vicinity 00214 sort(vicinity.begin(), vicinity.end(), ve_less); 00215 00216 vicinity_size = vicinity.size(); 00217 } 00218 00219 00221 //TODO// 00222 inline double sort_angle(double s, double c){ 00223 if (s==0) return (c>0) ? 0.0 : 2.0; 00224 double t=c/s; 00225 return (s>0) ? 1-t/(1+fabs(t)) : 3-t/(1+fabs(t)); 00226 } 00227 00228 00229 /* 00230 * append a particle to the 'vicinity' list after 00231 * having computed the angular-ordering quantities 00232 * - v vector to test 00233 **********************************************************/ 00234 void CSphvicinity::append_to_vicinity(CSphmomentum *v){ 00235 // skip the particle itself) 00236 if (v==parent) 00237 return; 00238 00239 int i=2*(v->index); 00240 00241 // compute the distance of the i-th particle with the parent 00242 double dot = dot_product3(parent_centre,*v); 00243 CSph3vector vnormal = *v; 00244 vnormal/=v->_norm; 00245 dot/=v->_norm; 00246 00247 // really check if the distance is less than VR 00248 if (dot>cosVR){ 00249 CSph3vector cross = cross_product3(parent_centre,vnormal); 00250 00251 // for the centres 00252 CSph3vector median = (parent_centre+vnormal); 00253 double amplT = sqrt((tan2R*(1+dot)+(dot-1))*(1+dot)); 00254 CSph3vector transverse = amplT*cross/cross._norm; 00255 00256 // first angle (+) 00257 ve_list[i].centre = median + transverse; 00258 ve_list[i].centre.build_norm(); 00259 ve_list[i].centre/=ve_list[i].centre._norm; 00260 CSph3vector diff = ve_list[i].centre - parent_centre; 00261 //ve_list[i].angle = atan2(dot_product3(angular_dir2, diff),dot_product3(angular_dir1, diff)); 00262 ve_list[i].angle = sort_angle(dot_product3(angular_dir2, diff),dot_product3(angular_dir1, diff)); 00263 ve_list[i].side = true; 00264 ve_list[i].cocircular.clear(); 00265 vicinity.push_back(&(ve_list[i])); 00266 00267 // second angle (-) 00268 ve_list[i+1].centre = median - transverse; 00269 ve_list[i+1].centre.build_norm(); 00270 ve_list[i+1].centre/=ve_list[i+1].centre._norm; 00271 diff = ve_list[i+1].centre - parent_centre; 00272 ve_list[i+1].angle = sort_angle(dot_product3(angular_dir2, diff),dot_product3(angular_dir1, diff)); 00273 ve_list[i+1].side = false; 00274 ve_list[i+1].cocircular.clear(); 00275 vicinity.push_back(&(ve_list[i+1])); 00276 00277 // now work out the cocircularity range for the two points (range 00278 // of angle within which the points stay within a distance 00279 // EPSILON_COCIRCULAR of circule 00280 // P = parent; C = child; O = Origin (center of circle) 00281 CSph3vector OP = parent_centre - ve_list[i+1].centre; 00282 CSph3vector OC = vnormal - ve_list[i+1].centre; 00283 00284 // two sources of error are (GPS CCN29-19) epsilon/(R sin theta) 00285 // and sqrt(2*epsilon/(R (1-cos theta))) and the way things work 00286 // out, it is the _smaller_ of the two that is relevant [NB have 00287 // changed definition of theta here relative to that used in 00288 // CCN29] [NB2: write things so as to avoid zero denominators and 00289 // to minimize the multiplications, divisions and above all sqrts 00290 // -- that means that c & s are defined including a factor of VR2] 00291 double inv_err1 = cross_product3(OP,OC)._norm * inv_R_EPS_COCIRC; 00292 double inv_err2_sq = (D2_R-dot_product3(OP,OC)) * inv_R_2EPS_COCIRC; 00293 ve_list[i].cocircular_range = siscone::pow2(inv_err1) > inv_err2_sq ? 00294 1.0/inv_err1 : 00295 sqrt(1.0/inv_err2_sq); 00296 ve_list[i+1].cocircular_range = ve_list[i].cocircular_range; 00297 } 00298 } 00299 00300 }