SISCone  2.0.5
siscone/spherical/protocones.cpp
00001 
00002 // File: protocones.cpp                                                      //
00003 // Description: source file for stable cones determination (Cstable_cones)   //
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:: 311                                                          $//
00026 // $Date:: 2011-10-05 23:27:09 +0200 (Wed, 05 Oct 2011)                     $//
00028 
00029 /*******************************************************
00030  * Introductory note:                                  *
00031  * Since this file has many member functions, we have  *
00032  * structured them in categories:                      *
00033  * INITIALISATION FUNCTIONS                            *
00034  *  - ctor()                                           *
00035  *  - ctor(particle_list)                              *
00036  *  - dtor()                                           *
00037  *  - init(particle_list)                              *
00038  * ALGORITHM MAIN ENTRY                                *
00039  *  - get_stable_cone(radius)                          *
00040  * ALGORITHM MAIN STEPS                                *
00041  *  - init_cone()                                      *
00042  *  - test_cone()                                      *
00043  *  - update_cone()                                    *
00044  *  - proceed_with_stability()                         *
00045  * ALGORITHM MAIN STEPS FOR COCIRCULAR SITUATIONS      *
00046  *  - cocircular_pt_less(v1, v2)                       *
00047  *  - prepare_cocircular_list()                        *
00048  *  - test_cone_cocircular()                           *
00049  *  - test_stability(candidate, border_list)           *
00050  *  - updat_cone_cocircular()                          *
00051  * RECOMPUTATION OF CONE CONTENTS                      *
00052  *  - compute_cone_contents()                          *
00053  *  - recompute_cone_contents()                        *
00054  *  - recompute_cone_contents_if_needed()              *
00055  * VARIOUS TOOLS                                       *
00056  *  - circle_intersect()                               *
00057  *  - is_inside()                                      *
00058  *  - abs_dangle()                                     *
00059  *******************************************************/
00060 
00061 #include <siscone/defines.h>
00062 #include <siscone/siscone_error.h>
00063 #include <siscone/circulator.h>
00064 #include "protocones.h"
00065 #include <math.h>
00066 #include <iostream>
00067 #include <algorithm>
00068 
00069 namespace siscone_spherical{
00070 
00071 using namespace std;
00072 
00073 /**********************************************************************
00074  * CSphstable_cones implementation                                    *
00075  * Computes the list of stable comes from a particle list.            *
00076  * This class does the first fundamental task of te cone algorithm:   *
00077  * it is used to compute the list of stable cones given a list        *
00078  * of particles.                                                      *
00079  **********************************************************************/
00080 
00082 // INITIALISATION FUNCTIONS                           //
00083 //  - ctor()                                          //
00084 //  - ctor(particle_list)                             //
00085 //  - dtor()                                          //
00086 //  - init(particle_list)                             //
00088 
00089 // default ctor
00090 //--------------
00091 CSphstable_cones::CSphstable_cones(){
00092   nb_tot = 0;
00093   hc = NULL;
00094 }
00095 
00096 // ctor with initialisation
00097 //--------------------------
00098 CSphstable_cones::CSphstable_cones(vector<CSphmomentum> &_particle_list)
00099   : CSphvicinity(_particle_list){
00100 
00101   nb_tot = 0;
00102   hc = NULL;
00103 }
00104 
00105 // default dtor
00106 //--------------
00107 CSphstable_cones::~CSphstable_cones(){
00108   if (hc!=NULL) delete hc;
00109 }
00110 
00111 /*
00112  * initialisation
00113  *  - _particle_list  list of particles
00114  *  - _n              number of particles
00115  *********************************************************************/
00116 void CSphstable_cones::init(vector<CSphmomentum> &_particle_list){
00117   // check already allocated mem
00118   if (hc!=NULL){
00119     delete hc;
00120   }
00121   if (protocones.size()!=0)
00122     protocones.clear();
00123 
00124   multiple_centre_done.clear();
00125 
00126   // initialisation
00127   set_particle_list(_particle_list);
00128 }
00129 
00130 
00132 // ALGORITHM MAIN ENTRY                               //
00133 //  - get_stable_cone(radius)                         //
00135 
00136 /*
00137  * compute stable cones.
00138  * This function really does the job i.e. computes
00139  * the list of stable cones (in a seedless way)
00140  *  - _radius:  radius of the cones
00141  * The number of stable cones found is returned
00142  *********************************************************************/
00143 int CSphstable_cones::get_stable_cones(double _radius){
00144   int p_idx;
00145 
00146   // check if everything is correctly initialised
00147   if (n_part==0){
00148     return 0;
00149   }
00150 
00151   R  = _radius;
00152   R2 = R*R;
00153   tan2R = tan(R);
00154   tan2R *= tan2R;
00155 
00156   // allow hash for cones candidates
00157   hc = new sph_hash_cones(n_part, R);
00158 
00159   // browse all particles
00160   for (p_idx=0;p_idx<n_part;p_idx++){
00161     // step 0: compute the child list CL.
00162     //         Note that this automatically sets the parent P
00163     build(&plist[p_idx], 2.0*R);
00164 
00165     // special case: 
00166     //   if the vicinity is empty, the parent particle is a 
00167     //   stable cone by itself. Add it to protocones list.
00168     if (vicinity_size==0){
00169       protocones.push_back(*parent);
00170       continue;
00171     }
00172 
00173 #ifdef DEBUG_STABLE_CONES
00174     cout << endl << endl;
00175     cout << "plot 'particles.dat' u 2:1 pt 1 ps 3" << endl;
00176     cout << "set label 1 'x' at " << parent->_phi << ", " << parent->_theta << endl;
00177 #endif
00178 
00179     // step 1: initialise with the first cone candidate
00180     init_cone();
00181 
00182     do{
00183       // step 2: test cone stability for that pair (P,C)
00184       test_cone();
00185 
00186       // step 3: go to the next cone child candidate C
00187     } while (!update_cone());
00188   }
00189 
00190   return proceed_with_stability();
00191 }
00192 
00193 
00195 // ALGORITHM MAIN STEPS                               //
00196 //  - init_cone()                                     //
00197 //  - test_cone()                                     //
00198 //  - update_cone()                                   //
00199 //  - proceed_with_stability()                        //
00201 
00202 /*
00203  * initialise the cone.
00204  * We take the first particle in the angular ordering to compute 
00205  * this one
00206  * return 0 on success, 1 on error
00207  *********************************************************************/
00208 int CSphstable_cones::init_cone(){
00209   // The previous version of the algorithm was starting the 
00210   // loop around vicinity elements with the "most isolated" child.
00211   // given the nodist method to calculate the cone contents, we no
00212   // longer need to worry about which cone comes first...
00213   first_cone=0;
00214 
00215   // now make sure we have lists of the cocircular particles
00216   prepare_cocircular_lists();
00217 
00218   //TODO? deal with a configuration with only degeneracies ? 
00219   // The only possibility seems a regular hexagon with a parent point
00220   // in the centre. And this situation is by itself unclear.
00221   // Hence, we do nothing here !
00222 
00223   // init set child C
00224   centre = vicinity[first_cone];
00225   child = centre->v;
00226   centre_idx = first_cone;
00227 
00228   // build the initial cone (nodist: avoids calculating distances --
00229   // just deduces contents by circulating around all in/out operations)
00230   // this function also sets the list of included particles
00231   compute_cone_contents();
00232   
00233   return 0;
00234 }
00235 
00236 
00237 /*
00238  * test cones.
00239  * We check if the cone(s) built with the present parent and child 
00240  * are stable
00241  * return 0 on success 1 on error
00242  *********************************************************************/
00243 int CSphstable_cones::test_cone(){
00244   siscone::Creference weighted_cone_ref;
00245   
00246   // depending on the side we are taking the child particle,
00247   // we test different configuration.
00248   // Each time, two configurations are tested in such a way that
00249   // all 4 possible cases (parent or child in or out the cone)
00250   // are tested when taking the pair of particle parent+child
00251   // and child+parent.
00252 
00253   // here are the tests entering the first series:
00254   //  1. check if the cone is already inserted
00255   //  2. check cone stability for the parent and child particles
00256   
00257   //UPDATED(see below): if (centre->side){
00258   //UPDATED(see below):   // test when both particles are not in the cone
00259   //UPDATED(see below):   // or when both are in.
00260   //UPDATED(see below):   // Note: for the totally exclusive case, test emptyness before
00261   //UPDATED(see below):   cone_candidate = cone;
00262   //UPDATED(see below):   if (cone.ref.not_empty()){
00263   //UPDATED(see below):     hc->insert(&cone_candidate, parent, child, false, false);
00264   //UPDATED(see below):   }
00265   //UPDATED(see below): 
00266   //UPDATED(see below):   cone_candidate = cone;
00267   //UPDATED(see below):   cone_candidate+= *parent + *child;
00268   //UPDATED(see below):   hc->insert(&cone_candidate, parent, child, true, true);
00269   //UPDATED(see below): } else {
00270   //UPDATED(see below):   // test when 1! of the particles is in the cone
00271   //UPDATED(see below):   cone_candidate = cone + *parent;
00272   //UPDATED(see below):   hc->insert(&cone_candidate, parent, child, true, false);
00273   //UPDATED(see below): 
00274   //UPDATED(see below):   cone_candidate = cone + *child;
00275   //UPDATED(see below):   hc->insert(&cone_candidate, parent, child, false, true);
00276   //UPDATED(see below): }
00277   //UPDATED(see below): 
00278   //UPDATED(see below): nb_tot+=2;
00279 
00280   // instead of testing 2 inclusion/exclusion states for every pair, we test the 4 of them
00281   // when the parent has an energy bigger than the child
00282   if (parent->E >= child->E){
00283     // test when both particles are not in the cone
00284     // Note: for the totally exclusive case, test emptiness before
00285     cone_candidate = cone;
00286     if (cone.ref.not_empty()){
00287       hc->insert(&cone_candidate, parent, child, false, false);
00288     }
00289 
00290     // test when 1! of the particles is in the cone
00291     cone_candidate += *parent;
00292     hc->insert(&cone_candidate, parent, child, true, false);
00293 
00294     cone_candidate  = cone;
00295     cone_candidate += *child;
00296     hc->insert(&cone_candidate, parent, child, false, true);
00297 
00298     // test when both are in.
00299     cone_candidate += *parent;
00300     hc->insert(&cone_candidate, parent, child, true, true);
00301     
00302     nb_tot += 4;
00303   }
00304 
00305   
00306   return 0;
00307 }
00308 
00309 
00310 /*
00311  * update the cone
00312  * go to the next child for that parent and update 'cone' appropriately
00313  * return 0 if update candidate found, 1 otherwise
00314  ***********************************************************************/
00315 int CSphstable_cones::update_cone(){
00316 #ifdef DEBUG_STABLE_CONES
00317   cout << "call 'circles_plot.gp' '" << centre->centre.px << "' '" 
00318        << centre->centre.py << "' '" << centre->centre.pz << "'" << endl
00319        << "pause -1 '(" << centre->angle << " " << (centre->side ? '+' : '-') << ")";
00320 #endif
00321 
00322   // get the next child and centre
00323   centre_idx++;
00324   if (centre_idx==vicinity_size)
00325     centre_idx=0;
00326   if (centre_idx==first_cone)
00327     return 1;
00328 
00329   // update the cone w.r.t. the old child
00330   // only required if the old child is entering inside in which
00331   // case we need to add it. We also know that the child is 
00332   // inside iff its side is -.
00333   if (!centre->side){
00334 #ifdef DEBUG_STABLE_CONES
00335     cout << " old_enter";
00336 #endif
00337     // update cone
00338     cone += (*child);
00339 
00340     // update info on particles inside
00341     centre->is_inside->cone = true;
00342 
00343     // update stability check quantities
00344     dpt += fabs(child->px)+fabs(child->py)+fabs(child->pz);
00345   }
00346 
00347   // update centre and child to correspond to the new position
00348   centre = vicinity[centre_idx];
00349   child = centre->v;
00350 
00351   // check cocircularity
00352   // note that if cocirculaity is detected (i.e. if we receive 1
00353   // in the next test), we need to recall 'update_cone' directly
00354   // since tests and remaining part of te update has been performed
00355   //if (cocircular_check())
00356   if (cocircular_check()){
00357 #ifdef DEBUG_STABLE_CONES
00358     cout << " Co-circular case detected" << endl;
00359 #endif
00360     return update_cone();
00361   }
00362 
00363   // update the cone w.r.t. the new child
00364   // only required if the new child was already inside in which
00365   // case we need to remove it. We also know that the child is 
00366   // inside iff its side is +.
00367   if ((centre->side) && (cone.ref.not_empty())){
00368 #ifdef DEBUG_STABLE_CONES
00369     cout << " new exit";
00370 #endif
00371 
00372     // update cone
00373     cone -= (*child);
00374 
00375     // update info on particles inside
00376     centre->is_inside->cone = false;
00377 
00378     // update stability check quantities
00379     dpt += fabs(child->px)+fabs(child->py)+fabs(child->pz); //child->perp2();
00380   }
00381 
00382   // check that the addition and subtraction of vectors does
00383   // not lead to too much rounding error
00384   // for that, we compute the sum of pt modifications and of |pt|
00385   // since last recomputation and once the ratio overpasses a threshold
00386   // we recompute vicinity.
00387   if ((dpt>PT_TSHOLD*(fabs(cone.px)+fabs(cone.py)+fabs(cone.pz))) && (cone.ref.not_empty())){
00388     recompute_cone_contents();
00389   }
00390   if (cone.ref.is_empty()){
00391     cone = CSphmomentum();
00392     dpt=0.0;
00393   }
00394 
00395 #ifdef DEBUG_STABLE_CONES
00396   cout << "'" << endl; 
00397 #endif
00398 
00399   return 0; 
00400 }
00401 
00402 
00403 /*
00404  * compute stability of all enumerated candidates.
00405  * For all candidate cones which are stable w.r.t. their border particles,
00406  * pass the last test: stability with quadtree intersection
00407  ************************************************************************/
00408 int CSphstable_cones::proceed_with_stability(){
00409   int i;
00410   sph_hash_element *elm;
00411 
00412   for (i=0;i<=hc->mask;i++){
00413     // test ith cell of the hash array
00414     elm = hc->hash_array[i];
00415 
00416     // browse elements therein
00417     while (elm!=NULL){
00418       // test stability
00419       if (elm->is_stable){
00420         // stability is not ensured by all pairs of "edges" already browsed
00421 #ifdef USE_QUADTREE_FOR_STABILITY_TEST
00422         //  => testing stability with quadtree intersection
00423         if (quadtree->circle_intersect(elm->eta, elm->phi, R2)==elm->ref)
00424 #else
00425         //  => testing stability with the particle-list intersection
00426         if (circle_intersect(elm->centre)==elm->centre.ref)
00427 #endif
00428           protocones.push_back(CSphmomentum(elm->centre,1.0));
00429       }
00430       
00431       // jump to the next one
00432       elm = elm->next;
00433     }
00434   }
00435   
00436   // free hash
00437   // we do that at this level because hash eats rather a lot of memory
00438   // we want to free it before running the split/merge algorithm
00439 #ifdef DEBUG_STABLE_CONES
00440   nb_hash_cones = hc->n_cones;
00441   nb_hash_occupied = hc->n_occupied_cells;
00442 #endif
00443 
00444   delete hc;
00445   hc=NULL;
00446 
00447   return protocones.size();
00448 }
00449 
00450 
00452 // ALGORITHM MAIN STEPS FOR COCIRCULAR SITUATIONS     //
00453 //  - cocircular_pt_less(v1, v2)                      //
00454 //  - prepare_cocircular_list()                       //
00455 //  - test_cone_cocircular()                          //
00456 //  - test_stability(candidate, border_vect)          //
00457 //  - updat_cone_cocircular()                         //
00459 
00461 //NEVER USED
00462 //bool cocircular_pt_less(CSphmomentum *v1, CSphmomentum *v2){
00463 //  return v1->perp2() < v2->perp2();
00464 //}
00465 
00466 /*
00467  * run through the vicinity of the current parent and for each child
00468  * establish which other members are cocircular... Note that the list
00469  * associated with each child contains references to vicinity
00470  * elements: thus two vicinity elements each associated with one given
00471  * particle may appear in a list -- this needs to be watched out for
00472  * later on... 
00473  **********************************************************************/
00474 void CSphstable_cones::prepare_cocircular_lists() {
00475   siscone::circulator<vector<CSphvicinity_elm*>::iterator > here(vicinity.begin(), 
00476                                                                  vicinity.begin(), 
00477                                                                  vicinity.end());
00478 
00479   siscone::circulator<vector<CSphvicinity_elm*>::iterator > search(here);
00480 
00481   do {
00482     CSphvicinity_elm* here_pntr = *here();
00483     search.set_position(here);
00484 
00485     // search forwards for things that should have "here" included in
00486     // their cocircularity list
00487     while (true) {
00488       ++search;
00489       if ( siscone::abs_dphi((*search())->angle, here_pntr->angle) < 
00490            here_pntr->cocircular_range 
00491            && search() != here()) {
00492         (*search())->cocircular.push_back(here_pntr);
00493       } else {
00494         break;
00495       }
00496     }
00497 
00498     // search backwards
00499     search.set_position(here);
00500     while (true) {
00501       --search;
00502       if ( siscone::abs_dphi((*search())->angle, here_pntr->angle) < 
00503            here_pntr->cocircular_range 
00504            && search() != here()) {
00505         (*search())->cocircular.push_back(here_pntr);
00506       } else {
00507         break;
00508       }
00509     }
00510 
00511     ++here;
00512   } while (here() != vicinity.begin());
00513 }
00514 
00515 /* 
00516  * Testing cocircular configurations in p^3 time,
00517  * rather than 2^p time; we will test all contiguous subsets of points
00518  * on the border --- note that this is till probably overkill, since
00519  * in principle we only have to test situations where up to a
00520  * half-circle is filled (but going to a full circle is simpler)
00521  ******************************************************************/
00522 void CSphstable_cones::test_cone_cocircular(CSphmomentum & borderless_cone,
00523                                             list<CSphmomentum *> & border_list) {
00524   // in spherical coordinates, we don't have a universal x-y axis system
00525   // to measure the angles. So we first determine one minimising
00526   // the uncertainties
00527   CSph3vector angl_dir1, angl_dir2;
00528   centre->centre.get_angular_directions(angl_dir1, angl_dir2);
00529   angl_dir1/=angl_dir1._norm;
00530   angl_dir2/=angl_dir2._norm;
00531 
00532   // now we have te reference axis, create the CSphborder_store structure
00533   vector<CSphborder_store> border_vect;
00534   border_vect.reserve(border_list.size());
00535   for (list<CSphmomentum *>::iterator it = border_list.begin();
00536        it != border_list.end(); it++) {
00537     border_vect.push_back(CSphborder_store(*it, centre->centre, angl_dir1, angl_dir2));
00538   }
00539 
00540   // get them into order of angle
00541   sort(border_vect.begin(), border_vect.end());
00542 
00543   // set up some circulators, since these will help us go around the
00544   // circle easily
00545   siscone::circulator<vector<CSphborder_store>::iterator > 
00546     start(border_vect.begin(), border_vect.begin(),border_vect.end());
00547   siscone::circulator<vector<CSphborder_store>::iterator > mid(start), end(start);
00548   
00549   // test the borderless cone
00550   CSphmomentum candidate = borderless_cone;
00551   //candidate.build_etaphi();
00552   if (candidate.ref.not_empty())
00553     test_stability(candidate, border_vect);
00554 
00555   do {
00556     // reset status wrt inclusion in the cone
00557     mid = start;
00558     do {
00559       mid()->is_in = false;
00560     } while (++mid != start);
00561 
00562     // now run over all inclusion possibilities with this starting point
00563     candidate = borderless_cone;
00564     while (++mid != start) { 
00565       // will begin with start+1 and go up to start-1
00566       mid()->is_in = true;
00567       candidate += *(mid()->mom);
00568       test_stability(candidate, border_vect);
00569     }
00570 
00571   } while (++start != end);
00572 
00573   // mid corresponds to momentum that we need to include to get the
00574   // full cone
00575   mid()->is_in = true;
00576   candidate += *(mid()->mom);
00577   test_stability(candidate, border_vect);
00578 }
00579 
00580 
00587 void CSphstable_cones::test_stability(CSphmomentum & candidate, const vector<CSphborder_store> & border_vect) {
00588   
00589   // this almost certainly has not been done...
00590   //candidate.build_etaphi();
00591 
00592   bool stable = true;
00593   for (unsigned i = 0; i < border_vect.size(); i++) {
00594     if (is_closer(&candidate, border_vect[i].mom,tan2R) ^ (border_vect[i].is_in)) {
00595       stable = false;
00596       break; // it's unstable so there's no point continuing
00597     }
00598   }
00599 
00600   if (stable) hc->insert(&candidate);
00601 }
00602 
00603 /*
00604  * check if we are in a situation of cocircularity.
00605  * if it is the case, update and test in the corresponding way
00606  * return 'false' if no cocircularity detected, 'true' otherwise
00607  * Note that if cocircularity is detected, we need to 
00608  * recall 'update' from 'update' !!!
00609  ***************************************************************/
00610 bool CSphstable_cones::cocircular_check(){
00611   // check if many configurations have the same centre.
00612   // if this is the case, branch on the algorithm for this
00613   // special case.
00614   // Note that those situation, being considered separately in 
00615   // test_cone_multiple, must only be considered here if all
00616   // angles are on the same side (this avoid multiple counting)
00617 
00618   if (centre->cocircular.empty()) return false;
00619 
00620   // first get cone into status required at end...
00621   if ((centre->side) && (cone.ref.not_empty())){
00622     // update cone
00623     cone -= (*child);
00624 
00625     // update info on particles inside
00626     centre->is_inside->cone = false;
00627 
00628     // update stability check quantities
00629     dpt += fabs(child->px)+fabs(child->py)+fabs(child->pz); //child->perp2();
00630   }
00631 
00632 
00633   // now establish the list of unique children in the list
00634   // first make sure parent and child are in!
00635 
00636   list<siscone::Cvicinity_inclusion *> removed_from_cone;
00637   list<siscone::Cvicinity_inclusion *> put_in_border;
00638   list<CSphmomentum *> border_list;
00639   
00640   CSphmomentum cone_removal;
00641   CSphmomentum border = *parent;
00642   border_list.push_back(parent);
00643 
00644   // make sure child appears in the border region
00645   centre->cocircular.push_back(centre);
00646 
00647   // now establish the full contents of the cone minus the cocircular
00648   // region and of the cocircular region itself
00649   for(list<CSphvicinity_elm *>::iterator it = centre->cocircular.begin();
00650       it != centre->cocircular.end(); it++) {
00651 
00652     if ((*it)->is_inside->cone) {
00653       cone_removal           += *((*it)->v);
00654       (*it)->is_inside->cone  = false;
00655       removed_from_cone.push_back((*it)->is_inside);
00656     }
00657 
00658     // if a point appears twice (i.e. with + and - sign) in the list of 
00659     // points on the border, we take care not to include it twice.
00660     // Note that this situation may appear when a point is at a distance
00661     // close to 2R from the parent
00662     if (!(*it)->is_inside->cocirc) {
00663       border += *((*it)->v);
00664       (*it)->is_inside->cocirc  = true;
00665       put_in_border.push_back((*it)->is_inside);
00666       border_list.push_back((*it)->v);
00667       //cout << "  adding particle " << (*it)->v->_theta << ", " << (*it)->v->_phi << " to the border list" << endl; 
00668     }
00669   }
00670 
00671 
00672   // figure out whether this pairing has been observed before
00673   CSphmomentum borderless_cone = cone;
00674   borderless_cone -= cone_removal;
00675   bool consider = true;
00676   for (unsigned int i=0;i<multiple_centre_done.size();i++){
00677     if ((multiple_centre_done[i].first ==borderless_cone.ref) &&
00678         (multiple_centre_done[i].second==border.ref))
00679       consider = false;
00680   }
00681 
00682   // now prepare the hard work
00683   if (consider) {
00684     // record the fact that we've now seen this combination
00685     multiple_centre_done.push_back(pair<siscone::Creference,siscone::Creference>(borderless_cone.ref, 
00686                                                                                  border.ref));
00687 
00688     // first figure out whether our cone momentum is good
00689     double local_dpt = fabs(cone_removal.px) + fabs(cone_removal.py);
00690     double total_dpt = dpt + local_dpt;
00691 
00692     recompute_cone_contents_if_needed(borderless_cone, total_dpt);
00693     if (total_dpt == 0) {
00694       // a recomputation has taken place -- so take advantage of this
00695       // and update the member cone momentum
00696       cone = borderless_cone + cone_removal;
00697       dpt  = local_dpt;
00698     }
00699 
00700     test_cone_cocircular(borderless_cone, border_list);
00701   }
00702 
00703 
00704   // relabel things that were in the cone but got removed
00705   for(list<siscone::Cvicinity_inclusion *>::iterator is_in = removed_from_cone.begin();
00706       is_in != removed_from_cone.end(); is_in++) {
00707     (*is_in)->cone = true;
00708   }
00709 
00710   // relabel things that got put into the border 
00711   for(list<siscone::Cvicinity_inclusion *>::iterator is_in = put_in_border.begin();
00712       is_in != put_in_border.end(); is_in++) {
00713     (*is_in)->cocirc = false;
00714   }
00715 
00716   // we're done with everything -- return true to signal to user that we've
00717   // been through the co-circularity rigmarole
00718   return true;
00719 }
00720 
00721 
00723 // RECOMPUTATION OF CONE CONTENTS                     //
00724 //  - compute_cone_contents()                         //
00725 //  - recompute_cone_contents()                       //
00726 //  - recompute_cone_contents_if_needed()             //
00728 
00737 void CSphstable_cones::compute_cone_contents() {
00738   siscone::circulator<vector<CSphvicinity_elm*>::iterator > 
00739     start(vicinity.begin()+first_cone, vicinity.begin(), vicinity.end());
00740 
00741   siscone::circulator<vector<CSphvicinity_elm*>::iterator > here(start);
00742 
00743   // note that in the following algorithm, the cone contents never includes
00744   // the child. Indeed, if it has positive sign, then it will be set as
00745   // outside at the last step in the loop. If it has negative sign, then the 
00746   // loop will at some point go to the corresponding situation with positive
00747   // sign and set the inclusion status to 0.
00748 
00749   do {
00750     // as we leave this position a particle enters if its side is
00751     // negative (i.e. the centre is the one at -ve angle wrt to the
00752     // parent-child line
00753     if (!(*here())->side) ((*here())->is_inside->cone) = 1;
00754     
00755     // move on to the next position
00756     ++here;
00757     
00758     // as we arrive at this position a particle leaves if its side is positive
00759     if ((*here())->side) ((*here())->is_inside->cone) = 0;
00760   } while (here != start);
00761 
00762   // once we've reached the start the 'is_inside' information should be
00763   // 100% complete, so we can use it to calculate the cone contents
00764   // and then exit
00765   recompute_cone_contents();
00766   return;
00767 
00768 }
00769 
00770 
00771 /*
00772  * compute the cone momentum from particle list.
00773  * in this version, we use the 'pincluded' information
00774  * from the CSphvicinity class
00775  */
00776 void CSphstable_cones::recompute_cone_contents(){
00777   unsigned int i;
00778 
00779   // set momentum to 0
00780   cone = CSphmomentum();
00781 
00782   // Important note: we can browse only the particles
00783   // in vicinity since all particles in the cone are
00784   // withing a distance 2R w.r.t. parent hence in vicinity.
00785   // Among those, we only add the particles for which 'is_inside' is true !
00786   // This methos rather than a direct comparison avoids rounding errors
00787   for (i=0;i<vicinity_size;i++){
00788     // to avoid double-counting, only use particles with + angle
00789     if ((vicinity[i]->side) && (vicinity[i]->is_inside->cone))
00790       cone += *vicinity[i]->v;
00791   }
00792   
00793   // set check variables back to 0
00794   dpt = 0.0;
00795 }
00796 
00797 
00798 /*
00799  * if we have gone beyond the acceptable threshold of change, compute
00800  * the cone momentum from particle list.  in this version, we use the
00801  * 'pincluded' information from the CSphvicinity class, but we don't
00802  * change the member cone, only the locally supplied one
00803  */
00804 void CSphstable_cones::recompute_cone_contents_if_needed(CSphmomentum & this_cone, 
00805                                                          double & this_dpt){
00806   
00807   if (this_dpt > PT_TSHOLD*(fabs(this_cone.px)+fabs(this_cone.py))) {
00808     if (cone.ref.is_empty()) {
00809       this_cone = CSphmomentum();
00810     } else {
00811       // set momentum to 0
00812       this_cone = CSphmomentum();
00813       
00814       // Important note: we can browse only the particles
00815       // in vicinity since all particles in the this_cone are
00816       // withing a distance 2R w.r.t. parent hence in vicinity.
00817       // Among those, we only add the particles for which 'is_inside' is true !
00818       // This methos rather than a direct comparison avoids rounding errors
00819       for (unsigned int i=0;i<vicinity_size;i++){
00820         // to avoid double-counting, only use particles with + angle
00821         if ((vicinity[i]->side) && (vicinity[i]->is_inside->cone))
00822           this_cone += *vicinity[i]->v;
00823       }
00824       
00825     }
00826     // set check variables back to 0
00827     this_dpt = 0.0;
00828   }
00829 
00830 }
00831 
00832 
00834 // VARIOUS TOOLS                                      //
00835 //  - circle_intersect()                              //
00836 //  - is_inside()                                     //
00837 //  - abs_dangle()                                    //
00839 
00840 
00841 /*
00842  * circle intersection.
00843  * computes the intersection with a circle of given centre and radius.
00844  * The output takes the form of a checkxor of the intersection's particles
00845  *  - cx    circle centre x coordinate
00846  *  - cy    circle centre y coordinate
00847  * return the checkxor for the intersection
00848  ******************************************************************/
00849 siscone::Creference CSphstable_cones::circle_intersect(CSph3vector &cone_centre){
00850   siscone::Creference intersection;
00851   int i;
00852 
00853   for (i=0;i<n_part;i++){
00854     // really check if the distance is less than R
00855     if (is_closer(&cone_centre, &(plist[i]), tan2R))
00856       intersection+=plist[i].ref;
00857   }
00858   
00859   return intersection;
00860 }
00861 
00862 }
The SISCone project has been developed by Gavin Salam and Gregory Soyez
Documentation generated on Mon Jun 4 2012 18:23:38 for SISCone by  Doxygen 1.7.6.1