Navigation

Main Page
Download
Support
Installation
Tutorial
Examples
Reference Manual
   Version 1.0.5new_solver
   Version 1.0.5dev
      Class Index
      File List
   Version 1.0.5b
   Version 1.0.4dev
   Version 1.0.4
Publications


Hosted by Get Ion Beam Simulator at SourceForge.net. Fast, secure and Free Open Source software downloads

particleiterator.hpp

Go to the documentation of this file.
00001 
00005 /* Copyright (c) 2005-2011 Taneli Kalvas. All rights reserved.
00006  *
00007  * You can redistribute this software and/or modify it under the terms
00008  * of the GNU General Public License as published by the Free Software
00009  * Foundation; either version 2 of the License, or (at your option)
00010  * any later version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00015  * General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this library (file "COPYING" included in the package);
00019  * if not, write to the Free Software Foundation, Inc., 51 Franklin
00020  * Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  * 
00022  * If you have questions about your rights to use or distribute this
00023  * software, please contact Berkeley Lab's Technology Transfer
00024  * Department at TTD@lbl.gov. Other questions, comments and bug
00025  * reports should be sent directly to the author via email at
00026  * taneli.kalvas@jyu.fi.
00027  * 
00028  * NOTICE. This software was developed under partial funding from the
00029  * U.S.  Department of Energy.  As such, the U.S. Government has been
00030  * granted for itself and others acting on its behalf a paid-up,
00031  * nonexclusive, irrevocable, worldwide license in the Software to
00032  * reproduce, prepare derivative works, and perform publicly and
00033  * display publicly.  Beginning five (5) years after the date
00034  * permission to assert copyright is obtained from the U.S. Department
00035  * of Energy, and subject to any subsequent five (5) year renewals,
00036  * the U.S. Government is granted for itself and others acting on its
00037  * behalf a paid-up, nonexclusive, irrevocable, worldwide license in
00038  * the Software to reproduce, prepare derivative works, distribute
00039  * copies to the public, perform publicly and display publicly, and to
00040  * permit others to do so.
00041  */
00042 
00043 #ifndef PARTICLEITERATOR_HPP
00044 #define PARTICLEITERATOR_HPP 1
00045 
00046 
00047 #include <vector>
00048 #include <iostream>
00049 #include <algorithm>
00050 #include <iomanip>
00051 #include <gsl/gsl_odeiv.h>
00052 #include <gsl/gsl_poly.h>
00053 #include "geometry.hpp"
00054 #include "compmath.hpp"
00055 #include "trajectory.hpp"
00056 #include "particles.hpp"
00057 #include "vectorfield.hpp"
00058 #include "scalarfield.hpp"
00059 #include "scharge.hpp"
00060 #include "scheduler.hpp"
00061 #include "polysolver.hpp"
00062 #include "particledatabase.hpp"
00063 
00064 
00065 //#define DEBUG_PARTICLE_ITERATOR 1
00066 
00067 
00070 enum particle_iterator_type_e {
00071     PARTICLE_ITERATOR_ADAPTIVE = 0,
00072     PARTICLE_ITERATOR_FIXED_STEP_LEN
00073 };
00074 
00075 
00084 template <class PP> class ColData {
00085 public:
00086     PP                _x;         
00087     int               _dir;       
00092     ColData( PP x, int dir ) : _x(x), _dir(dir) {}
00093     
00098     bool operator<( const ColData &cd ) const {
00099         return( _x[0] < cd._x[0] );
00100     }
00101 
00110     static void build_coldata_linear( std::vector<ColData> &coldata, const Mesh &mesh,
00111                                       const PP &x1, const PP &x2 ) {
00112         
00113         coldata.clear();
00114 
00115         for( size_t a = 0; a < PP::dim(); a++ ) {
00116             
00117             int a1 = (int)floor( (x1[2*a+1]-mesh.origo(a))/mesh.h() );
00118             int a2 = (int)floor( (x2[2*a+1]-mesh.origo(a))/mesh.h() );
00119             if( a1 > a2 ) {
00120                 int a = a2;
00121                 a2 = a1;
00122                 a1 = a;
00123             }
00124             
00125             for( int b = a1+1; b <= a2; b++ ) {
00126         
00127                 // Save intersection coordinates
00128                 double K = (b*mesh.h() + mesh.origo(a) - x1[2*a+1]) / 
00129                     (x2[2*a+1] - x1[2*a+1]);
00130                 if( K < 0.0 ) K = 0.0;
00131                 else if( K > 1.0 ) K = 1.0;
00132                 //std::cout << "Found valid root: " << K << "\n";
00133 
00134                 if( x2[2*a+1] > x1[2*a+1] )
00135                     coldata.push_back( ColData( x1 + (x2-x1)*K, a+1 ) );
00136                 else
00137                     coldata.push_back( ColData( x1 + (x2-x1)*K, -a-1 ) );
00138             }
00139         }
00140 
00141         // Sort intersections in increasing time order
00142         sort( coldata.begin(), coldata.end() );
00143     }
00144 
00153     static void build_coldata_poly( std::vector<ColData> &coldata, const Mesh &mesh,
00154                                     const PP &x1, const PP &x2 ) {
00155         
00156 #ifdef DEBUG_PARTICLE_ITERATOR
00157         std::cout << "Building coldata using polynomial interpolation\n";
00158 #endif
00159 
00160         coldata.clear();
00161 
00162         // Construct trajectory representation
00163         TrajectoryRep1D traj[PP::dim()];
00164         for( size_t a = 0; a < PP::dim(); a++ ) {
00165             traj[a].construct( x2[0]-x1[0], 
00166                                x1[2*a+1], x1[2*a+2], 
00167                                x2[2*a+1], x2[2*a+2] );
00168         }
00169 
00170         // Solve trajectory intersections
00171         for( size_t a = 0; a < PP::dim(); a++ ) {
00172 
00173             // Mesh number of x1 (start point)
00174             int i = (int)floor( (x1[2*a+1]-mesh.origo(a))/mesh.h() );
00175             
00176             // Search to negative (dj = -1) and positive (dj = +1) mesh directions
00177             for( int dj = -1; dj <= 1; dj += 2 ) {
00178                 int j = i;
00179                 if( dj == +1 )
00180                     j = i+1;
00181                 int Kcount;  // Solution counter
00182                 double K[3]; // Solution array
00183                 while( 1 ) {
00184 
00185                     // Intersection point
00186                     double val = mesh.origo(a) + mesh.h() * j;
00187                     if( val < mesh.origo(a) )
00188                         break;
00189                     else if( val > mesh.max(a) )
00190                         break;
00191 
00192 #ifdef DEBUG_PARTICLE_ITERATOR
00193                     std::cout << "  Searching intersections at coord(" << a << ") = " << val << "\n";
00194 #endif
00195                     Kcount = traj[a].solve( K, val );
00196                     if( Kcount == 0 )
00197                         break; // No valid roots
00198 
00199 #ifdef DEBUG_PARTICLE_ITERATOR
00200                     std::cout << "  Found " << Kcount << " valid roots: ";
00201                     for( int p = 0; p < Kcount; p++ )
00202                         std::cout << K[p] << " ";
00203                     std::cout << "\n";
00204 #endif
00205 
00206                     // Save roots to coldata
00207                     for( int b = 0; b < Kcount; b++ ) {
00208                         PP xcol;
00209                         double x, v;
00210                         xcol(0) = x1[0] + K[b]*(x2[0]-x1[0]);
00211                         for( size_t c = 0; c < PP::dim(); c++ ) {
00212                             traj[c].coord( x, v, K[b] );
00213                             if( a == c )
00214                                 xcol[2*c+1] = val; // limit numerical inaccuracy
00215                             else
00216                                 xcol[2*c+1] = x;
00217                             xcol[2*c+2] = v;
00218                         }
00219                         if( mesh.geom_mode() == MODE_CYL )
00220                             xcol[5] = x1[5] + K[b]*(x2[5]-x1[5]);
00221                         if( xcol[2*a+2] >= 0.0 )
00222                             coldata.push_back( ColData( xcol, a+1 ) );
00223                         else
00224                             coldata.push_back( ColData( xcol, -a-1 ) );
00225                     }
00226 
00227                     j += dj;
00228                 }
00229             }
00230         }
00231 
00232         // Sort intersections in increasing time order
00233         sort( coldata.begin(), coldata.end() );
00234 
00235 #ifdef DEBUG_PARTICLE_ITERATOR
00236         std::cout << "  Coldata built\n";
00237 #endif
00238     }
00239 
00240 };
00241 
00242 
00250 template <class PP> class ParticleIterator {
00251 
00252     gsl_odeiv_system           _system;    
00253     gsl_odeiv_step            *_step;      
00254     gsl_odeiv_control         *_control;   
00255     gsl_odeiv_evolve          *_evolve;    
00257     particle_iterator_type_e   _type;      
00259     bool                       _polyint;   
00260     double                     _epsabs;    
00261     double                     _epsrel;    
00262     uint32_t                   _maxsteps;  
00263     double                     _maxt;      
00264     uint32_t                   _trajdiv;   
00266     bool                       _mirror[6]; 
00268     ParticleIteratorData       _pidata;    
00269     const TrajectoryHandlerCallback *_thand_cb; 
00270     const TrajectoryEndCallback     *_tend_cb;  
00271     const TrajectoryEndCallback     *_bsup_cb;  
00272     ParticleDataBase          *_pdb;            
00273     pthread_mutex_t           *_scharge_mutex;  
00275     PP                         _xi;        
00277     std::vector<PP>            _traj;      
00278     std::vector<ColData<PP> >  _coldata;   
00280     ParticleStatistics         _stat;      
00288     void save_trajectory_point( PP x ) {
00289 
00290         try {
00291             _traj.push_back( x );
00292         } catch( std::bad_alloc ) {
00293             throw( ErrorNoMem( ERROR_LOCATION, "Out of memory saving trajectory" ) );
00294         }
00295     }
00296 
00305     bool check_collision( Particle<PP> &particle, const PP &x1, const PP &x2, PP &status_x ) {
00306 
00307         // If inside solid, bracket for collision point
00308         Vec3D v2 = x2.location();
00309         int32_t bound = _pidata._geom->inside( v2 );
00310         if( bound < 7 )
00311             return( true ); // No collision happened.
00312         Vec3D vc;
00313         Vec3D v1 = x1.location();
00314         double K = _pidata._geom->bracket_surface( bound, v2, v1, vc );
00315 
00316         // Calculate new PP
00317         for( size_t a = 0; a < PP::size(); a++ )
00318             status_x[a] = x2[a] + K*(x1[a]-x2[a]);
00319 
00320         // Remove all points from trajectory after time status_x[0].
00321         for( size_t a = _traj.size()-1; a > 0; a-- ) {
00322             if( _traj[a][0] > status_x[0] )
00323                 _traj.pop_back();
00324             else
00325                 break;
00326         }
00327 
00328         // Save last trajectory point and update status
00329         //save_trajectory_point( status_x );
00330         particle.set_status( PARTICLE_COLL );
00331 
00332         // Update collision statistics for boundary
00333         _stat.add_bound_collision( bound, particle.IQ() );
00334 
00335         return( false ); // Collision happened.
00336     }
00337 
00338 
00346     void handle_mirror( size_t c, int i[3], size_t a, int border, PP &x2 ) {
00347 
00348 #ifdef DEBUG_PARTICLE_ITERATOR
00349         std::cout << "    handle_mirror( c = " << c 
00350                   << ", i = (" << i[0] << ", " << i[1] << ", " << i[2]
00351                   << "), a = " << a << ", border = " << border 
00352                   << ")\n";
00353 #endif
00354 
00355         double xmirror;
00356         if( border < 0 ) {
00357             xmirror = _pidata._geom->origo(a);
00358             i[a] = -i[a]-1;
00359         } else {
00360             xmirror = _pidata._geom->max(a);
00361             i[a] = 2*_pidata._geom->size(a)-i[a]-3;
00362         }
00363 
00364 #ifdef DEBUG_PARTICLE_ITERATOR
00365         std::cout << "    xmirror = " << xmirror << "\n";
00366         std::cout << "    i = (" << i[0] << ", " << i[1] << ", " << i[2] << ")\n";
00367         std::cout << "    xi = " << _xi << "\n";
00368 #endif
00369         
00370         // Check if found edge at first encounter
00371         bool caught_at_boundary = false;
00372         if( _coldata[c]._dir == border*((int)a+1) && 
00373             ( i[a] == 0 || i[a] == (int)_pidata._geom->size(a)-2 ) ) {
00374             caught_at_boundary = true;
00375 #ifdef DEBUG_PARTICLE_ITERATOR
00376             std::cout << "   caught_at_boundary\n";
00377 #endif
00378         }
00379 
00380         // Mirror traj back to _xi
00381         if( caught_at_boundary ) {
00382             save_trajectory_point( _coldata[c]._x );
00383         } else {
00384             for( int b = _traj.size()-1; b > 0; b-- ) {
00385                 if( _traj[b][0] >= _xi[0] ) {
00386                     
00387 #ifdef DEBUG_PARTICLE_ITERATOR
00388                     std::cout << "    mirroring traj[" << b << "] = " << _traj[b] << "\n";
00389 #endif
00390                     _traj[b][2*a+1] = 2.0*xmirror - _traj[b][2*a+1];
00391                     _traj[b][2*a+2] *= -1.0;
00392                 } else
00393                     break;
00394             }
00395         }
00396 
00397         // Mirror rest of the coldata
00398         for( size_t b = c; b < _coldata.size(); b++ ) {
00399             if( (size_t)abs(_coldata[b]._dir) == a+1 )
00400                 _coldata[b]._dir *= -1;
00401             _coldata[b]._x[2*a+1] = 2.0*xmirror - _coldata[b]._x[2*a+1];
00402             _coldata[b]._x[2*a+2] *= -1.0;
00403         }
00404 
00405         if( caught_at_boundary )
00406             save_trajectory_point( _coldata[c]._x );
00407 
00408         // Mirror calculation point
00409         x2[2*a+1] = 2.0*xmirror - x2[2*a+1];
00410         x2[2*a+2] *= -1.0;
00411         
00412         // Coordinates changed, reset integrator
00413         gsl_odeiv_step_reset( _step );
00414         gsl_odeiv_evolve_reset( _evolve );
00415     }
00416 
00417 
00418     void handle_collision( Particle<PP> &particle, uint32_t bound, size_t c, PP &status_x ) {
00419 
00420 #ifdef DEBUG_PARTICLE_ITERATOR
00421         std::cout << "    handle_collision()\n";
00422 #endif
00423 
00424         //save_trajectory_point( _coldata[c]._x );
00425         status_x = _coldata[c]._x;
00426         particle.set_status( PARTICLE_OUT );
00427         _stat.add_bound_collision( bound, particle.IQ() );
00428     }
00429 
00430 
00439     bool handle_trajectory_advance( Particle<PP> &particle, size_t c, int i[3], PP &x2 ) {
00440 
00441         // Check for collisions with solids and advance coordinates i.
00442         if( PP::dim() == 2 ) {
00443             if( _coldata[c]._dir == -1 ) {
00444                 if( ( abs(_pidata._geom->mesh(i[0],  i[1]  )) >= 7 || 
00445                       abs(_pidata._geom->mesh(i[0],  i[1]+1)) >= 7 ) &&
00446                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00447                     return( false );
00448                 i[0]--;
00449             } else if( _coldata[c]._dir == +1 ) {
00450                 if( ( abs(_pidata._geom->mesh(i[0]+1,i[1]  )) >= 7 || 
00451                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1)) >= 7 ) &&
00452                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00453                     return( false );
00454                 i[0]++;
00455             } else if( _coldata[c]._dir == -2 ) {
00456                 if( ( abs(_pidata._geom->mesh(i[0],  i[1]  )) >= 7 || 
00457                       abs(_pidata._geom->mesh(i[0]+1,i[1]  )) >= 7 ) &&
00458                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00459                     return( false );
00460                 i[1]--;
00461             } else {
00462                 if( ( abs(_pidata._geom->mesh(i[0],  i[1]+1)) >= 7 || 
00463                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1)) >= 7 ) &&
00464                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00465                     return( false );
00466                 i[1]++;
00467             }
00468         } else if( PP::dim() == 3 ) {
00469             if( _coldata[c]._dir == -1 ) {
00470                 if( ( abs(_pidata._geom->mesh(i[0],  i[1],  i[2]  )) >= 7 || 
00471                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]  )) >= 7 ||
00472                       abs(_pidata._geom->mesh(i[0],  i[1],  i[2]+1)) >= 7 ||
00473                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]+1)) >= 7 ) &&
00474                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00475                     return( false );
00476                 i[0]--;
00477             } else if( _coldata[c]._dir == +1 ) {
00478                 if( ( abs(_pidata._geom->mesh(i[0]+1,i[1],  i[2]  )) >= 7 || 
00479                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]  )) >= 7 ||
00480                       abs(_pidata._geom->mesh(i[0]+1,i[1],  i[2]+1)) >= 7 ||
00481                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]+1)) >= 7 ) &&
00482                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00483                     return( false );
00484                 i[0]++;
00485             } else if( _coldata[c]._dir == -2 ) {
00486                 if( ( abs(_pidata._geom->mesh(i[0],  i[1],i[2]  )) >= 7 || 
00487                       abs(_pidata._geom->mesh(i[0]+1,i[1],i[2]  )) >= 7 ||
00488                       abs(_pidata._geom->mesh(i[0],  i[1],i[2]+1)) >= 7 ||
00489                       abs(_pidata._geom->mesh(i[0]+1,i[1],i[2]+1)) >= 7 ) &&
00490                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00491                     return( false );
00492                 i[1]--;
00493             } else if( _coldata[c]._dir == +2 ) {
00494                 if( ( abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]  )) >= 7 || 
00495                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]  )) >= 7 ||
00496                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]+1)) >= 7 ||
00497                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]+1)) >= 7 ) &&
00498                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00499                     return( false );
00500                 i[1]++;
00501             } else if( _coldata[c]._dir == -3 ) {
00502                 if( ( abs(_pidata._geom->mesh(i[0],  i[1],  i[2]  )) >= 7 || 
00503                       abs(_pidata._geom->mesh(i[0]+1,i[1],  i[2]  )) >= 7 ||
00504                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2])) >= 7 ||
00505                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2])) >= 7 ) &&
00506                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00507                     return( false );
00508                 i[2]--;
00509             } else {
00510                 if( ( abs(_pidata._geom->mesh(i[0],  i[1],  i[2]+1)) >= 7 || 
00511                       abs(_pidata._geom->mesh(i[0]+1,i[1],  i[2]+1)) >= 7 ||
00512                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]+1)) >= 7 ||
00513                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]+1)) >= 7 ) &&
00514                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00515                     return( false );
00516                 i[2]++;
00517             }
00518         } else {
00519             throw( Error( ERROR_LOCATION, "unsupported dimension number" ) );
00520         }
00521         
00522         // Check for collisions/mirroring with simulation boundary. Here
00523         // coordinates i are already advanced to next mesh.
00524         for( size_t a = 0; a < PP::dim(); a++ ) {
00525 
00526             if( i[a] < 0 ) {
00527                 if( _mirror[2*a] )
00528                     handle_mirror( c, i, a, -1, x2 );
00529                 else {
00530                     handle_collision( particle, 1+2*a, c, x2 );
00531                     return( false );
00532                 }
00533             } else if( i[a] >= (_pidata._geom->size(a)-1) ) {
00534                 if( _mirror[2*a+1] )
00535                     handle_mirror( c, i, a, +1, x2 );
00536                 else {
00537                     handle_collision( particle, 2+2*a, c, x2 );
00538                     return( false );
00539                 }
00540             }
00541         }
00542 
00543         return( true );
00544     }
00545 
00551     bool limit_trajectory_advance( const PP &x1, PP &x2 ) {
00552 
00553         bool touched = false;
00554 
00555         for( size_t a = 0; a < PP::dim(); a++ ) {
00556 
00557             double lim1 = _pidata._geom->origo(a) - 
00558                 (_pidata._geom->size(a)-1)*_pidata._geom->h();
00559             double lim2 = _pidata._geom->origo(a) + 
00560                 2*(_pidata._geom->size(a)-1)*_pidata._geom->h();
00561 
00562             if( x2[2*a+1] < lim1 ) {
00563                 
00564                 double K = (lim1 - x1[2*a+1]) / (x2[2*a+1] - x1[2*a+1]);
00565                 x2 = x1 + K*(x2-x1);
00566                 touched = true;
00567 #ifdef DEBUG_PARTICLE_ITERATOR
00568                 std::cout << "Limiting step to:\n";
00569                 std::cout << "  x2: " << x2 << "\n";
00570 #endif
00571             } else if(x2[2*a+1] > lim2 ) {
00572 
00573                 double K = (lim2 - x1[2*a+1]) / (x2[2*a+1] - x1[2*a+1]);
00574                 x2 = x1 + K*(x2-x1);
00575                 touched = true;
00576 #ifdef DEBUG_PARTICLE_ITERATOR
00577                 std::cout << "Limiting step to:\n";
00578                 std::cout << "  x2: " << x2 << "\n";
00579 #endif
00580             }
00581         }
00582 
00583         return( touched );
00584     }
00585 
00590     void build_coldata( bool force_linear, const PP &x1, const PP &x2 ) {
00591 
00592         try {
00593             if( _polyint && !force_linear )
00594                 ColData<PP>::build_coldata_poly( _coldata, *_pidata._geom, x1, x2 );
00595             else
00596                 ColData<PP>::build_coldata_linear( _coldata, *_pidata._geom, x1, x2 );
00597         } catch( std::bad_alloc ) {
00598             throw( ErrorNoMem( ERROR_LOCATION, "Out of memory building ColData" ) );
00599         }
00600 
00601     }
00602 
00622     bool handle_trajectory( Particle<PP> &particle, const PP &x1, PP &x2, 
00623                             bool force_linear, bool first_step ) {
00624 
00625 #ifdef DEBUG_PARTICLE_ITERATOR
00626         std::cout << "Handle trajectory from x1 to x2:\n";
00627         std::cout << "  x1: " << x1 << "\n";
00628         std::cout << "  x2: " << x2 << "\n";
00629 #endif
00630 
00631         // Limit trajectory advance to double the simulation box
00632         // If limitation done, force to linear interpolation
00633         if( limit_trajectory_advance( x1, x2 ) )
00634             force_linear = true;
00635 
00636         build_coldata( force_linear, x1, x2 );
00637 
00638         // TODO
00639         // Remove entrance to geometry if coming from outside or make
00640         // code to skip the collision detection for these particles
00641 
00642         // No intersections, nothing to do
00643         if( _coldata.size() == 0 ) {
00644 #ifdef DEBUG_PARTICLE_ITERATOR
00645             std::cout << "No coldata\n";
00646 #endif
00647             return( true );
00648         }
00649 
00650         // Starting mesh index
00651         int i[3] = {0, 0, 0};
00652         for( size_t cdir = 0; cdir < PP::dim(); cdir++ )
00653             i[cdir] = (int)floor( (x1[2*cdir+1]-_pidata._geom->origo(cdir))/_pidata._geom->h() );
00654 
00655         // Process intersection points
00656 #ifdef DEBUG_PARTICLE_ITERATOR
00657         std::cout << "Process coldata points:\n";
00658 #endif
00659         for( size_t a = 0; a < _coldata.size(); a++ ) {
00660 
00661 #ifdef DEBUG_PARTICLE_ITERATOR
00662             std::cout << "  Coldata " << std::setw(4) << a << ": " 
00663                       << _coldata[a]._x << ", " 
00664                       << std::setw(3) << i[0] << " "
00665                       << std::setw(3) << i[1] << " "
00666                       << std::setw(3) << i[2] << " "
00667                       << std::setw(3) << _coldata[a]._dir << "\n";
00668 #endif
00669 
00670             // Advance particle in mesh, check for possible collisions and
00671             // do mirroring.
00672             handle_trajectory_advance( particle, a, i, x2 );
00673 
00674             // Update space charge for one mesh.
00675             if( _pidata._scharge )
00676                 scharge_add_from_trajectory( *_pidata._scharge, _scharge_mutex, particle.IQ(), 
00677                                              _xi, _coldata[a]._x );
00678 
00679             // Call trajectory handler callback
00680             if( _thand_cb )
00681                 (*_thand_cb)( &particle, &_coldata[a]._x, &x2 );
00682 
00683 #ifdef DEBUG_PARTICLE_ITERATOR
00684             if( particle.get_status() == PARTICLE_OUT ) {
00685                 std::cout << "  Particle out\n";
00686                 std::cout << "  x = " << x2 << "\n";
00687             } else if( particle.get_status() == PARTICLE_COLL ) {
00688                 std::cout << "  Particle collided\n";
00689                 std::cout << "  x = " << x2 << "\n";
00690             }
00691 #endif
00692             // Clear coldata and exit if particle collided.
00693             if( particle.get_status() != PARTICLE_OK ) {
00694                 save_trajectory_point( x2 );
00695                 _coldata.clear();
00696                 return( false );
00697             }
00698 
00699             // Update last intersection point xi.
00700             _xi = _coldata[a]._x;
00701         }
00702 
00703 #ifdef DEBUG_PARTICLE_ITERATOR
00704         std::cout << "Coldata done\n";
00705 #endif
00706         _coldata.clear();
00707         return( true );
00708     }
00709 
00710 
00713      bool axis_mirror_required( const PP &x2 ) {
00714          return( _pidata._geom->geom_mode() == MODE_CYL && 
00715                  x2[4] < 0.0 && 
00716                  x2[3] <= 0.01*_pidata._geom->h() &&
00717                  x2[3]*fabs(x2[5]) <= 1.0e-9*fabs(x2[4]) );
00718                  
00719      }
00720 
00721 
00727     bool handle_axis_mirror_step( Particle<PP> &particle, const PP &x1, PP &x2 ) {
00728 
00729         // Get acceleration at x2
00730         double dxdt[5];
00731         PP::get_derivatives( x2[0], &x2[1], dxdt, (void *)&_pidata );
00732 
00733         // Calculate crossover point assuming zero acceleration in
00734         // r-direction and constant acceleration in x-direction
00735         double dt = -x2[3]/x2[4];
00736         PP xc;
00737         xc[0] = x2[0]+dt;
00738         xc[1] = x2[1]+(x2[2]+0.5*dxdt[1]*dt)*dt;
00739         xc[2] = x2[2];
00740         xc[3] = x2[3]+x2[4]*dt;
00741         xc[4] = x2[4];
00742         xc[5] = x2[5];
00743 
00744         // Mirror x2 to x3
00745         PP x3 = 2*xc - x2;
00746         x3[3] *= -1.0;
00747         x3[4] *= -1.0;
00748         x3[5] *= -1.0;
00749 
00750 #ifdef DEBUG_PARTICLE_ITERATOR
00751         std::cout << "Particle mirror:\n";
00752         std::cout << "  x1: " << x1 << "\n";
00753         std::cout << "  x2: " << x2 << "\n";
00754         std::cout << "  xc: " << xc << "\n";
00755         std::cout << "  x3: " << x3 << "\n";
00756 #endif
00757         
00758         // Handle step with linear interpolation to avoid going to r<=0
00759         if( !handle_trajectory( particle, x2, x3, true, false ) )
00760             return( false ); // Particle done
00761 
00762         // Save trajectory calculation points
00763         save_trajectory_point( x2 );
00764         save_trajectory_point( xc );
00765         xc[4] *= -1.0;
00766         xc[5] *= -1.0;
00767         save_trajectory_point( xc );
00768         
00769         // Next step not a continuation of previous one, reset
00770         // integrator
00771         gsl_odeiv_step_reset( _step );
00772         gsl_odeiv_evolve_reset( _evolve );
00773 
00774         // Continue iteration at mirrored point
00775         x2 = x3;
00776         return( true );
00777     }
00778     
00792     bool check_particle_definition( PP &x ) {
00793 
00794 #ifdef DEBUG_PARTICLE_ITERATOR
00795         std::cout << "Particle defined at:\n";
00796         std::cout << "  x = " << x << "\n";
00797 #endif
00798 
00799         // Check for NaN
00800         for( size_t a = 0; a < PP::size(); a++ ) {
00801             if( comp_isnan( x[a] ) )
00802                 return( false );
00803         }
00804 
00805         // Check if inside solids or outside simulation geometry box.
00806         if( _pidata._geom->inside( x.location() ) )
00807             return( false );
00808 
00809         // Check if particle on simulation geometry border and directed outwards
00810         /*
00811         for( size_t a = 0; a < PP::dim(); a++ ) {
00812             if( x[2*a+1] == _pidata._geom->origo(a) && x[2*a+2] < 0.0 ) {
00813                 if( _mirror[2*a] ) {
00814                     x[2*a+2] *= -1.0;
00815 #ifdef DEBUG_PARTICLE_ITERATOR
00816         std::cout << "Mirroring to:\n";
00817         std::cout << "  x = " << x << "\n";
00818 #endif
00819                 } else {
00820                     return( false );
00821                 }
00822 
00823             } else if( x[2*a+1] == _pidata._geom->max(a) & x[2*a+2] > 0.0 ) {
00824                 if( _mirror[2*a+1] ) {
00825                     x[2*a+2] *= -1.0;
00826 #ifdef DEBUG_PARTICLE_ITERATOR
00827         std::cout << "Mirroring to:\n";
00828         std::cout << "  x = " << x << "\n";
00829 #endif
00830                 } else {
00831                     return( false );
00832                 }
00833             }
00834         }
00835 
00836 #ifdef DEBUG_PARTICLE_ITERATOR
00837         std::cout << "Definition ok\n";
00838 #endif
00839 
00840         */
00841         return( true );
00842     }
00843     
00844     double calculate_dt( const PP &x, const double *dxdt ) {
00845 
00846         double spd = 0.0, acc = 0.0;
00847 
00848         for( size_t a = 0; a < (PP::size()-1)/2; a++ ) {
00849             //std::cout << "spd += " << dxdt[2*a]*dxdt[2*a] << "\n";
00850             spd += dxdt[2*a]*dxdt[2*a];
00851             //std::cout << "acc += " << dxdt[2*a+1]*dxdt[2*a+1] << "\n";
00852             acc += dxdt[2*a+1]*dxdt[2*a+1];
00853         }
00854         if( _pidata._geom->geom_mode() == MODE_CYL ) {
00855             //std::cout << "MODE_CYL\n";
00856             //std::cout << "spd += " << x[3]*x[3]*x[5]*x[5] << "\n";
00857             spd += x[3]*x[3]*x[5]*x[5];
00858             //std::cout << "acc += " << x[3]*x[3]*dxdt[4]*dxdt[4] << "\n";
00859             acc += x[3]*x[3]*dxdt[4]*dxdt[4];
00860         }
00861         //std::cout << "spd = " << sqrt(spd) << "\n";
00862         //std::cout << "acc = " << sqrt(acc) << "\n";
00863         spd = _pidata._geom->h() / sqrt(spd);
00864         acc = sqrt( 2.0*_pidata._geom->h() / sqrt(acc) );
00865 
00866         return( spd < acc ? spd : acc );
00867     }
00868 
00869 public:
00870 
00897     ParticleIterator( particle_iterator_type_e type, double epsabs, double epsrel, 
00898                       bool polyint, uint32_t maxsteps, double maxt, 
00899                       uint32_t trajdiv, bool mirror[6], ScalarField *scharge, 
00900                       pthread_mutex_t *scharge_mutex,
00901                       const VectorField *efield, const VectorField *bfield, 
00902                       const Geometry *geom ) 
00903         : _type(type), _polyint(polyint), _epsabs(epsabs), _epsrel(epsrel), _maxsteps(maxsteps), _maxt(maxt), 
00904           _trajdiv(trajdiv), _pidata(scharge,efield,bfield,geom), 
00905           _thand_cb(0), _tend_cb(0), _bsup_cb(0), _pdb(0), _scharge_mutex(scharge_mutex), 
00906           _stat(geom->number_of_boundaries()) {
00907         
00908         // Initialize mirroring
00909         _mirror[0] = mirror[0];
00910         _mirror[1] = mirror[1];
00911         _mirror[2] = mirror[2];
00912         _mirror[3] = mirror[3];
00913         _mirror[4] = mirror[4];
00914         _mirror[5] = mirror[5];
00915 
00916         // Initialize system of ordinary differential equations (ODE)
00917         _system.jacobian  = NULL;
00918         _system.params    = (void *)&_pidata;
00919         _system.function  = PP::get_derivatives;
00920         _system.dimension = PP::size()-1; // Time is not part of differential equation dimensions
00921 
00922         // Make scale
00923         // 2D:  x vx y vy
00924         // Cyl: x vx r vr omega
00925         // 3D:  x vx y vy z vz
00926         double scale_abs[PP::size()-1];
00927         for( uint32_t a = 0; a < (uint32_t)PP::size()-2; a+=2 ) {
00928             scale_abs[a+0] = 1.0;
00929             scale_abs[a+1] = 1.0e6;
00930         }
00931         if( _pidata._geom->geom_mode() == MODE_CYL )
00932             scale_abs[4] = 1.0;
00933 
00934         // Initialize ODE solver
00935         _step    = gsl_odeiv_step_alloc( gsl_odeiv_step_rkck, _system.dimension );
00936         //_control = gsl_odeiv_control_standard_new( _epsabs, _epsrel, 1.0, 1.0 );
00937         _control = gsl_odeiv_control_scaled_new( _epsabs, _epsrel, 1.0, 1.0, scale_abs, PP::size()-1 );
00938         _evolve  = gsl_odeiv_evolve_alloc( _system.dimension );
00939     }
00940 
00941 
00944     ~ParticleIterator() {
00945         gsl_odeiv_evolve_free( _evolve );
00946         gsl_odeiv_control_free( _control );
00947         gsl_odeiv_step_free( _step );
00948     }
00949 
00950 
00953     void set_trajectory_handler_callback( const TrajectoryHandlerCallback *thand_cb ) {
00954         _thand_cb = thand_cb;
00955     }
00956 
00957 
00960     void set_trajectory_end_callback( const TrajectoryEndCallback *tend_cb, ParticleDataBase *pdb ) {
00961         _tend_cb = tend_cb;
00962         _pdb = pdb;
00963     }
00964 
00965 
00968     void set_bfield_suppression_callback( const CallbackFunctorD_V *bsup_cb ) {
00969         _pidata.set_bfield_suppression_callback( bsup_cb );
00970     }
00971 
00974     void set_relativistic( bool enable ) {
00975         _pidata.set_relativistic( enable );
00976     }
00977 
00980     const ParticleStatistics &get_statistics( void ) const {
00981         return( _stat );
00982     }
00983 
00984     
00993     void operator()( Particle<PP> *particle, uint32_t pi ) {
00994 
00995         // Check particle status
00996         if( particle->get_status() != PARTICLE_OK )
00997             return;
00998 
00999         // Copy starting point to x and 
01000         PP x = particle->x();
01001 
01002         // Check particle definition
01003         if( !check_particle_definition( x ) ) {
01004             particle->set_status( PARTICLE_BADDEF );
01005             _stat.inc_end_baddef();
01006             return;
01007         }
01008         particle->x() = x;
01009 
01010         // Reset trajectory and save first trajectory point.
01011         _traj.clear();
01012         save_trajectory_point( x );
01013 #ifdef DEBUG_PARTICLE_ITERATOR
01014         std::cout << x[0] << " " 
01015                   << x[1] << " " 
01016                   << x[2] << " " 
01017                   << x[3] << " " 
01018                   << x[4] << "\n";
01019 #endif
01020         _pidata._qm = particle->qm();
01021         _xi = x;
01022 
01023         // Reset integrator
01024         gsl_odeiv_step_reset( _step );
01025         gsl_odeiv_evolve_reset( _evolve );
01026         
01027         // Make initial guess for step size
01028         //std::cout << "Guess dt ------------------------------------------------\n";
01029         double dxdt[PP::size()-1];
01030         PP::get_derivatives( 0.0, &x[1], dxdt, (void *)&_pidata );
01031         double dt = calculate_dt( x, dxdt );
01032 
01033 #ifdef DEBUG_PARTICLE_ITERATOR
01034         std::cout << "dxdt = ";
01035         for( size_t a = 0; a < PP::size()-1; a++ )
01036             std::cout  << dxdt[a] << " ";
01037         std::cout << "\n";
01038         std::cout << "dt = " << dt << "\n";
01039         std::cout << "*** Starting iteration\n";
01040 #endif
01041         
01042         // Iterate ODEs until maximum steps are done, time is used 
01043         // or particle collides.
01044         PP x2;
01045         size_t nstp = 0; // Steps taken
01046         while( nstp < _maxsteps && x[0] < _maxt ) {
01047 
01048 #ifdef DEBUG_PARTICLE_ITERATOR
01049             std::cout << "\n*** Step ***\n";
01050             std::cout << "  x  = " << x2 << "\n";
01051             std::cout << "  dt = " << dt << " (proposed)\n";
01052 #endif
01053             
01054             // Take a step.
01055             x2 = x;
01056 
01057             while( true ) {
01058                 int retval = gsl_odeiv_evolve_apply( _evolve, _control, _step, &_system, 
01059                                                      &x2[0], _maxt, &dt, &x2[1] );
01060                 if( retval == IBSIMU_DERIV_ERROR ) {
01061 #ifdef DEBUG_PARTICLE_ITERATOR
01062                     std::cout << "Step rejected\n";
01063                     std::cout << "  x2 = " << x2 << "\n";
01064                     std::cout << "  dt = " << dt << "\n";
01065 #endif
01066                     x2[0] = x[0]; // Reset time (this shouldn't be necessary - there 
01067                                   // is a bug in GSL-1.12, report has been sent)
01068                     dt *= 0.5;
01069                     if( dt == 0.0 )
01070                         throw( Error( ERROR_LOCATION, "too small step size" ) );
01071                     //nstp++;
01072                     continue;
01073                 } else if( retval == GSL_SUCCESS ) {
01074                     break;
01075                 } else {
01076                     throw( Error( ERROR_LOCATION, "gsl_odeiv_evolve_apply failed" ) );
01077                 }
01078             }
01079             
01080             // Check step count number and step size validity
01081             if( nstp >= _maxsteps )
01082                 break;
01083             if( x2[0] == x[0] )
01084                 throw( Error( ERROR_LOCATION, "too small step size" ) );
01085 
01086 #ifdef DEBUG_PARTICLE_ITERATOR
01087             std::cout << "Step accepted from x1 to x2:\n";
01088             std::cout << "  dt = " << dt << " (taken)\n";
01089             std::cout << "  x1 = " << x << "\n";
01090             std::cout << "  x2 = " << x2 << "\n";
01091 #endif
01092 
01093             // Handle collisions and space charge of step.
01094             if( !handle_trajectory( *particle, x, x2, false, nstp == 0 ) ) {
01095                 x = x2;
01096                 break; // Particle done
01097             }
01098 
01099             // Check if particle mirroring is required to avoid 
01100             // singularity at symmetry axis.
01101             if( axis_mirror_required( x2 ) ) {
01102                 if( !handle_axis_mirror_step( *particle, x, x2 ) )
01103                     break; // Particle done
01104             }
01105 
01106             // Propagate coordinates
01107             x = x2;
01108 
01109             // Save trajectory point
01110             save_trajectory_point( x2 );
01111             
01112             // Increase step count.
01113             nstp++;
01114         }
01115 
01116 #ifdef DEBUG_PARTICLE_ITERATOR
01117         std::cout << "\n*** Done stepping ***\n";
01118 #endif
01119 
01120         // Check if step count or time limited 
01121         if( nstp == _maxsteps ) {
01122             particle->set_status( PARTICLE_NSTP );
01123             _stat.inc_end_step();
01124         } else if( x[0] >= _maxt ) {
01125             particle->set_status( PARTICLE_TIME );
01126             _stat.inc_end_time();
01127         }
01128 
01129         // Save step count
01130         _stat.inc_sum_steps( nstp );
01131 
01132         // Save trajectory of current particle
01133         if( _trajdiv != 0 && pi % _trajdiv == 0 )
01134             particle->copy_trajectory( _traj );
01135 
01136         // Save last particle location
01137         particle->x() = x;
01138 
01139         // Call trajectory end callback
01140         if( _tend_cb )
01141             (*_tend_cb)( particle, _pdb );
01142     }
01143 
01144 };
01145 
01146 
01147 #endif
01148 


Reference manual for Ion Beam Simulator 1.0.5dev
Generated by Doxygen 1.7.1 on Mon Feb 6 2012 15:07:16.