Navigation

Main Page
Download
Support
Installation
Tutorial
Examples
Reference Manual
   Version 1.0.4
   Version 1.0.4dev
      Class Index
      File List
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 "trajectory.hpp"
00055 #include "particles.hpp"
00056 #include "vectorfield.hpp"
00057 #include "scalarfield.hpp"
00058 #include "scharge.hpp"
00059 #include "scheduler.hpp"
00060 #include "polysolver.hpp"
00061 #include "particledatabase.hpp"
00062 
00063 
00064 //#define DEBUG_PARTICLE_ITERATOR 1
00065 
00066 
00069 enum particle_iterator_type_e {
00070     PARTICLE_ITERATOR_ADAPTIVE = 0,
00071     PARTICLE_ITERATOR_FIXED_STEP_LEN
00072 };
00073 
00074 
00083 template <class PP> class ColData {
00084 public:
00085     PP                _x;         
00086     int               _dir;       
00091     ColData( PP x, int dir ) : _x(x), _dir(dir) {}
00092     
00097     bool operator<( const ColData &cd ) const {
00098         return( _x[0] < cd._x[0] );
00099     }
00100 
00109     static void build_coldata_linear( std::vector<ColData> &coldata, const Mesh &mesh,
00110                                       const PP &x1, const PP &x2 ) {
00111         
00112         coldata.clear();
00113 
00114         for( size_t a = 0; a < PP::dim(); a++ ) {
00115             
00116             int a1 = (int)floor( (x1[2*a+1]-mesh.origo(a))/mesh.h() );
00117             int a2 = (int)floor( (x2[2*a+1]-mesh.origo(a))/mesh.h() );
00118             if( a1 > a2 ) {
00119                 int a = a2;
00120                 a2 = a1;
00121                 a1 = a;
00122             }
00123             
00124             for( int b = a1+1; b <= a2; b++ ) {
00125         
00126                 // Save intersection coordinates
00127                 double K = (b*mesh.h() + mesh.origo(a) - x1[2*a+1]) / 
00128                     (x2[2*a+1] - x1[2*a+1]);
00129                 if( K < 0.0 ) K = 0.0;
00130                 else if( K > 1.0 ) K = 1.0;
00131                 //std::cout << "Found valid root: " << K << "\n";
00132 
00133                 if( x2[2*a+1] > x1[2*a+1] )
00134                     coldata.push_back( ColData( x1 + (x2-x1)*K, a+1 ) );
00135                 else
00136                     coldata.push_back( ColData( x1 + (x2-x1)*K, -a-1 ) );
00137             }
00138         }
00139 
00140         // Sort intersections in increasing time order
00141         sort( coldata.begin(), coldata.end() );
00142     }
00143 
00152     static void build_coldata_poly( std::vector<ColData> &coldata, const Mesh &mesh,
00153                                     const PP &x1, const PP &x2 ) {
00154         
00155 #ifdef DEBUG_PARTICLE_ITERATOR
00156         std::cout << "Building coldata using polynomial interpolation\n";
00157 #endif
00158 
00159         coldata.clear();
00160 
00161         // Construct trajectory representation
00162         TrajectoryRep1D traj[PP::dim()];
00163         for( size_t a = 0; a < PP::dim(); a++ ) {
00164             traj[a].construct( x2[0]-x1[0], 
00165                                x1[2*a+1], x1[2*a+2], 
00166                                x2[2*a+1], x2[2*a+2] );
00167         }
00168 
00169         // Solve trajectory intersections
00170         for( size_t a = 0; a < PP::dim(); a++ ) {
00171 
00172             // Mesh number of x1 (start point)
00173             int i = (int)floor( (x1[2*a+1]-mesh.origo(a))/mesh.h() );
00174             
00175             // Search to negative (dj = -1) and positive (dj = +1) mesh directions
00176             for( int dj = -1; dj <= 1; dj += 2 ) {
00177                 int j = i;
00178                 if( dj == +1 )
00179                     j = i+1;
00180                 int Kcount;  // Solution counter
00181                 double K[3]; // Solution array
00182                 while( 1 ) {
00183 
00184                     // Intersection point
00185                     double val = mesh.origo(a) + mesh.h() * j;
00186                     if( val < mesh.origo(a) )
00187                         break;
00188                     else if( val > mesh.max(a) )
00189                         break;
00190 
00191 #ifdef DEBUG_PARTICLE_ITERATOR
00192                     std::cout << "  Searching intersections at coord(" << a << ") = " << val << "\n";
00193 #endif
00194                     Kcount = traj[a].solve( K, val );
00195                     if( Kcount == 0 )
00196                         break; // No valid roots
00197 
00198 #ifdef DEBUG_PARTICLE_ITERATOR
00199                     std::cout << "  Found " << Kcount << " valid roots: ";
00200                     for( int p = 0; p < Kcount; p++ )
00201                         std::cout << K[p] << " ";
00202                     std::cout << "\n";
00203 #endif
00204 
00205                     // Save roots to coldata
00206                     for( int b = 0; b < Kcount; b++ ) {
00207                         PP xcol;
00208                         double x, v;
00209                         xcol(0) = x1[0] + K[b]*(x2[0]-x1[0]);
00210                         for( size_t c = 0; c < PP::dim(); c++ ) {
00211                             traj[c].coord( x, v, K[b] );
00212                             if( a == c )
00213                                 xcol[2*c+1] = val; // limit numerical inaccuracy
00214                             else
00215                                 xcol[2*c+1] = x;
00216                             xcol[2*c+2] = v;
00217                         }
00218                         if( mesh.geom_mode() == MODE_CYL )
00219                             xcol[5] = x1[5] + K[b]*(x2[5]-x1[5]);
00220                         if( xcol[2*a+2] >= 0.0 )
00221                             coldata.push_back( ColData( xcol, a+1 ) );
00222                         else
00223                             coldata.push_back( ColData( xcol, -a-1 ) );
00224                     }
00225 
00226                     j += dj;
00227                 }
00228             }
00229         }
00230 
00231         // Sort intersections in increasing time order
00232         sort( coldata.begin(), coldata.end() );
00233 
00234 #ifdef DEBUG_PARTICLE_ITERATOR
00235         std::cout << "  Coldata built\n";
00236 #endif
00237     }
00238 
00239 };
00240 
00241 
00249 template <class PP> class ParticleIterator {
00250 
00251     gsl_odeiv_system           _system;    
00252     gsl_odeiv_step            *_step;      
00253     gsl_odeiv_control         *_control;   
00254     gsl_odeiv_evolve          *_evolve;    
00256     particle_iterator_type_e   _type;      
00258     bool                       _polyint;   
00259     double                     _epsabs;    
00260     double                     _epsrel;    
00261     uint32_t                   _maxsteps;  
00262     double                     _maxt;      
00263     uint32_t                   _trajdiv;   
00265     bool                       _mirror[6]; 
00267     ParticleIteratorData       _pidata;    
00268     const TrajectoryHandlerCallback *_thand_cb; 
00269     const TrajectoryEndCallback     *_tend_cb;  
00270     const TrajectoryEndCallback     *_bsup_cb;  
00271     ParticleDataBase          *_pdb;            
00272     pthread_mutex_t           *_scharge_mutex;  
00274     PP                         _xi;        
00276     std::vector<PP>            _traj;      
00277     std::vector<ColData<PP> >  _coldata;   
00279     ParticleStatistics         _stat;      
00290     bool check_collision( Particle<PP> &particle, const PP &x1, const PP &x2, PP &status_x ) {
00291 
00292         // If inside solid, bracket for collision point
00293         Vec3D v2 = x2.location();
00294         int32_t bound = _pidata._geom->inside( v2 );
00295         if( bound < 7 )
00296             return( true ); // No collision happened.
00297         Vec3D vc;
00298         Vec3D v1 = x1.location();
00299         double K = _pidata._geom->bracket_surface( bound, v2, v1, vc );
00300 
00301         // Calculate new PP
00302         for( size_t a = 0; a < PP::size(); a++ )
00303             status_x[a] = x2[a] + K*(x1[a]-x2[a]);
00304 
00305         // Remove all points from trajectory after time status_x[0].
00306         for( size_t a = _traj.size()-1; a > 0; a-- ) {
00307             if( _traj[a][0] > status_x[0] )
00308                 _traj.pop_back();
00309             else
00310                 break;
00311         }
00312 
00313         // Save last trajectory point and update status
00314         //_traj.push_back( status_x );
00315         particle.set_status( PARTICLE_COLL );
00316 
00317         // Update collision statistics for boundary
00318         _stat.add_bound_collision( bound, particle.IQ() );
00319 
00320         return( false ); // Collision happened.
00321     }
00322 
00323 
00331     void handle_mirror( size_t c, int i[3], size_t a, int border, PP &x2 ) {
00332 
00333 #ifdef DEBUG_PARTICLE_ITERATOR
00334         std::cout << "    handle_mirror( c = " << c 
00335                   << ", i = (" << i[0] << ", " << i[1] << ", " << i[2]
00336                   << "), a = " << a << ", border = " << border 
00337                   << ")\n";
00338 #endif
00339 
00340         double xmirror;
00341         if( border < 0 ) {
00342             xmirror = _pidata._geom->origo(a);
00343             i[a] = -i[a]-1;
00344         } else {
00345             xmirror = _pidata._geom->max(a);
00346             i[a] = 2*_pidata._geom->size(a)-i[a]-3;
00347         }
00348 
00349 #ifdef DEBUG_PARTICLE_ITERATOR
00350         std::cout << "    xmirror = " << xmirror << "\n";
00351         std::cout << "    i = (" << i[0] << ", " << i[1] << ", " << i[2] << ")\n";
00352         std::cout << "    xi = " << _xi << "\n";
00353 #endif
00354         
00355         // Check if found edge at first encounter
00356         bool caught_at_boundary = false;
00357         if( _coldata[c]._dir == border*((int)a+1) && 
00358             ( i[a] == 0 || i[a] == (int)_pidata._geom->size(a)-2 ) ) {
00359             caught_at_boundary = true;
00360 #ifdef DEBUG_PARTICLE_ITERATOR
00361             std::cout << "   caught_at_boundary\n";
00362 #endif
00363         }
00364 
00365         // Mirror traj back to _xi
00366         if( caught_at_boundary ) {
00367             _traj.push_back( _coldata[c]._x );
00368         } else {
00369             for( int b = _traj.size()-1; b > 0; b-- ) {
00370                 if( _traj[b][0] >= _xi[0] ) {
00371                     
00372 #ifdef DEBUG_PARTICLE_ITERATOR
00373                     std::cout << "    mirroring traj[" << b << "] = " << _traj[b] << "\n";
00374 #endif
00375                     _traj[b][2*a+1] = 2.0*xmirror - _traj[b][2*a+1];
00376                     _traj[b][2*a+2] *= -1.0;
00377                 } else
00378                     break;
00379             }
00380         }
00381 
00382         // Mirror rest of the coldata
00383         for( size_t b = c; b < _coldata.size(); b++ ) {
00384             if( (size_t)abs(_coldata[b]._dir) == a+1 )
00385                 _coldata[b]._dir *= -1;
00386             _coldata[b]._x[2*a+1] = 2.0*xmirror - _coldata[b]._x[2*a+1];
00387             _coldata[b]._x[2*a+2] *= -1.0;
00388         }
00389 
00390         if( caught_at_boundary )
00391             _traj.push_back( _coldata[c]._x );
00392 
00393         // Mirror calculation point
00394         x2[2*a+1] = 2.0*xmirror - x2[2*a+1];
00395         x2[2*a+2] *= -1.0;
00396         
00397         // Coordinates changed, reset integrator
00398         gsl_odeiv_step_reset( _step );
00399         gsl_odeiv_evolve_reset( _evolve );
00400     }
00401 
00402 
00403     void handle_collision( Particle<PP> &particle, uint32_t bound, size_t c, PP &status_x ) {
00404 
00405 #ifdef DEBUG_PARTICLE_ITERATOR
00406         std::cout << "    handle_collision()\n";
00407 #endif
00408 
00409         //_traj.push_back( _coldata[c]._x );
00410         status_x = _coldata[c]._x;
00411         particle.set_status( PARTICLE_OUT );
00412         _stat.add_bound_collision( bound, particle.IQ() );
00413     }
00414 
00415 
00424     bool handle_trajectory_advance( Particle<PP> &particle, size_t c, int i[3], PP &x2 ) {
00425 
00426         // Check for collisions with solids and advance coordinates i.
00427         if( PP::dim() == 2 ) {
00428             if( _coldata[c]._dir == -1 ) {
00429                 if( ( abs(_pidata._geom->mesh(i[0],  i[1]  )) >= 7 || 
00430                       abs(_pidata._geom->mesh(i[0],  i[1]+1)) >= 7 ) &&
00431                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00432                     return( false );
00433                 i[0]--;
00434             } else if( _coldata[c]._dir == +1 ) {
00435                 if( ( abs(_pidata._geom->mesh(i[0]+1,i[1]  )) >= 7 || 
00436                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1)) >= 7 ) &&
00437                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00438                     return( false );
00439                 i[0]++;
00440             } else if( _coldata[c]._dir == -2 ) {
00441                 if( ( abs(_pidata._geom->mesh(i[0],  i[1]  )) >= 7 || 
00442                       abs(_pidata._geom->mesh(i[0]+1,i[1]  )) >= 7 ) &&
00443                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00444                     return( false );
00445                 i[1]--;
00446             } else {
00447                 if( ( abs(_pidata._geom->mesh(i[0],  i[1]+1)) >= 7 || 
00448                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1)) >= 7 ) &&
00449                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00450                     return( false );
00451                 i[1]++;
00452             }
00453         } else if( PP::dim() == 3 ) {
00454             if( _coldata[c]._dir == -1 ) {
00455                 if( ( abs(_pidata._geom->mesh(i[0],  i[1],  i[2]  )) >= 7 || 
00456                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]  )) >= 7 ||
00457                       abs(_pidata._geom->mesh(i[0],  i[1],  i[2]+1)) >= 7 ||
00458                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]+1)) >= 7 ) &&
00459                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00460                     return( false );
00461                 i[0]--;
00462             } else if( _coldata[c]._dir == +1 ) {
00463                 if( ( abs(_pidata._geom->mesh(i[0]+1,i[1],  i[2]  )) >= 7 || 
00464                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]  )) >= 7 ||
00465                       abs(_pidata._geom->mesh(i[0]+1,i[1],  i[2]+1)) >= 7 ||
00466                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]+1)) >= 7 ) &&
00467                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00468                     return( false );
00469                 i[0]++;
00470             } else if( _coldata[c]._dir == -2 ) {
00471                 if( ( abs(_pidata._geom->mesh(i[0],  i[1],i[2]  )) >= 7 || 
00472                       abs(_pidata._geom->mesh(i[0]+1,i[1],i[2]  )) >= 7 ||
00473                       abs(_pidata._geom->mesh(i[0],  i[1],i[2]+1)) >= 7 ||
00474                       abs(_pidata._geom->mesh(i[0]+1,i[1],i[2]+1)) >= 7 ) &&
00475                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00476                     return( false );
00477                 i[1]--;
00478             } else if( _coldata[c]._dir == +2 ) {
00479                 if( ( abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]  )) >= 7 || 
00480                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]  )) >= 7 ||
00481                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]+1)) >= 7 ||
00482                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]+1)) >= 7 ) &&
00483                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00484                     return( false );
00485                 i[1]++;
00486             } else if( _coldata[c]._dir == -3 ) {
00487                 if( ( abs(_pidata._geom->mesh(i[0],  i[1],  i[2]  )) >= 7 || 
00488                       abs(_pidata._geom->mesh(i[0]+1,i[1],  i[2]  )) >= 7 ||
00489                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2])) >= 7 ||
00490                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2])) >= 7 ) &&
00491                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00492                     return( false );
00493                 i[2]--;
00494             } else {
00495                 if( ( abs(_pidata._geom->mesh(i[0],  i[1],  i[2]+1)) >= 7 || 
00496                       abs(_pidata._geom->mesh(i[0]+1,i[1],  i[2]+1)) >= 7 ||
00497                       abs(_pidata._geom->mesh(i[0],  i[1]+1,i[2]+1)) >= 7 ||
00498                       abs(_pidata._geom->mesh(i[0]+1,i[1]+1,i[2]+1)) >= 7 ) &&
00499                     !check_collision( particle, _xi, _coldata[c]._x, x2 ) )
00500                     return( false );
00501                 i[2]++;
00502             }
00503         } else {
00504             throw( Error( ERROR_LOCATION, "unsupported dimension number" ) );
00505         }
00506         
00507         // Check for collisions/mirroring with simulation boundary. Here
00508         // coordinates i are already advanced to next mesh.
00509         for( size_t a = 0; a < PP::dim(); a++ ) {
00510 
00511             if( i[a] < 0 ) {
00512                 if( _mirror[2*a] )
00513                     handle_mirror( c, i, a, -1, x2 );
00514                 else {
00515                     handle_collision( particle, 1+2*a, c, x2 );
00516                     return( false );
00517                 }
00518             } else if( i[a] >= (_pidata._geom->size(a)-1) ) {
00519                 if( _mirror[2*a+1] )
00520                     handle_mirror( c, i, a, +1, x2 );
00521                 else {
00522                     handle_collision( particle, 2+2*a, c, x2 );
00523                     return( false );
00524                 }
00525             }
00526         }
00527 
00528         return( true );
00529     }
00530 
00536     bool limit_trajectory_advance( const PP &x1, PP &x2 ) {
00537 
00538         bool touched = false;
00539 
00540         for( size_t a = 0; a < PP::dim(); a++ ) {
00541 
00542             double lim1 = _pidata._geom->origo(a) - 
00543                 (_pidata._geom->size(a)-1)*_pidata._geom->h();
00544             double lim2 = _pidata._geom->origo(a) + 
00545                 2*(_pidata._geom->size(a)-1)*_pidata._geom->h();
00546 
00547             if( x2[2*a+1] < lim1 ) {
00548                 
00549                 double K = (lim1 - x1[2*a+1]) / (x2[2*a+1] - x1[2*a+1]);
00550                 x2 = x1 + K*(x2-x1);
00551                 touched = true;
00552 #ifdef DEBUG_PARTICLE_ITERATOR
00553                 std::cout << "Limiting step to:\n";
00554                 std::cout << "  x2: " << x2 << "\n";
00555 #endif
00556             } else if(x2[2*a+1] > lim2 ) {
00557 
00558                 double K = (lim2 - x1[2*a+1]) / (x2[2*a+1] - x1[2*a+1]);
00559                 x2 = x1 + K*(x2-x1);
00560                 touched = true;
00561 #ifdef DEBUG_PARTICLE_ITERATOR
00562                 std::cout << "Limiting step to:\n";
00563                 std::cout << "  x2: " << x2 << "\n";
00564 #endif
00565             }
00566         }
00567 
00568         return( touched );
00569     }
00570 
00590     bool handle_trajectory( Particle<PP> &particle, const PP &x1, PP &x2, 
00591                             bool force_linear, bool first_step ) {
00592 
00593 #ifdef DEBUG_PARTICLE_ITERATOR
00594         std::cout << "Handle trajectory from x1 to x2:\n";
00595         std::cout << "  x1: " << x1 << "\n";
00596         std::cout << "  x2: " << x2 << "\n";
00597 #endif
00598 
00599         // Limit trajectory advance to double the simulation box
00600         // If limitation done, force to linear interpolation
00601         if( limit_trajectory_advance( x1, x2 ) )
00602             force_linear = true;
00603 
00604         // Make coldata
00605         if( _polyint && !force_linear )
00606             ColData<PP>::build_coldata_poly( _coldata, *_pidata._geom, x1, x2 );
00607         else
00608             ColData<PP>::build_coldata_linear( _coldata, *_pidata._geom, x1, x2 );
00609 
00610         // TODO
00611         // Remove entrance to geometry if coming from outside or make
00612         // code to skip the collision detection for these particles
00613 
00614         // No intersections, nothing to do
00615         if( _coldata.size() == 0 ) {
00616 #ifdef DEBUG_PARTICLE_ITERATOR
00617             std::cout << "No coldata\n";
00618 #endif
00619             return( true );
00620         }
00621 
00622         // Starting mesh index
00623         int i[3] = {0, 0, 0};
00624         for( size_t cdir = 0; cdir < PP::dim(); cdir++ )
00625             i[cdir] = (int)floor( (x1[2*cdir+1]-_pidata._geom->origo(cdir))/_pidata._geom->h() );
00626 
00627         // Process intersection points
00628 #ifdef DEBUG_PARTICLE_ITERATOR
00629         std::cout << "Process coldata points:\n";
00630 #endif
00631         for( size_t a = 0; a < _coldata.size(); a++ ) {
00632 
00633 #ifdef DEBUG_PARTICLE_ITERATOR
00634             std::cout << "  Coldata " << std::setw(4) << a << ": " 
00635                       << _coldata[a]._x << ", " 
00636                       << std::setw(3) << i[0] << " "
00637                       << std::setw(3) << i[1] << " "
00638                       << std::setw(3) << i[2] << " "
00639                       << std::setw(3) << _coldata[a]._dir << "\n";
00640 #endif
00641 
00642             // Advance particle in mesh, check for possible collisions and
00643             // do mirroring.
00644             handle_trajectory_advance( particle, a, i, x2 );
00645 
00646             // Update space charge for one mesh.
00647             if( _pidata._scharge )
00648                 scharge_add_from_trajectory( *_pidata._scharge, _scharge_mutex, particle.IQ(), 
00649                                              _xi, _coldata[a]._x );
00650 
00651             // Call trajectory handler callback
00652             if( _thand_cb )
00653                 (*_thand_cb)( &particle, &_coldata[a]._x, &x2 );
00654 
00655 #ifdef DEBUG_PARTICLE_ITERATOR
00656             if( particle.get_status() == PARTICLE_OUT ) {
00657                 std::cout << "  Particle out\n";
00658                 std::cout << "  x = " << x2 << "\n";
00659             } else if( particle.get_status() == PARTICLE_COLL ) {
00660                 std::cout << "  Particle collided\n";
00661                 std::cout << "  x = " << x2 << "\n";
00662             }
00663 #endif
00664             // Clear coldata and exit if particle collided.
00665             if( particle.get_status() != PARTICLE_OK ) {
00666                 _traj.push_back( x2 );
00667                 _coldata.clear();
00668                 return( false );
00669             }
00670 
00671             // Update last intersection point xi.
00672             _xi = _coldata[a]._x;
00673         }
00674 
00675 #ifdef DEBUG_PARTICLE_ITERATOR
00676         std::cout << "Coldata done\n";
00677 #endif
00678         _coldata.clear();
00679         return( true );
00680     }
00681 
00682 
00685      bool axis_mirror_required( const PP &x2 ) {
00686          return( _pidata._geom->geom_mode() == MODE_CYL && 
00687                  x2[4] < 0.0 && 
00688                  x2[3] <= 0.01*_pidata._geom->h() &&
00689                  x2[3]*fabs(x2[5]) <= 1.0e-9*fabs(x2[4]) );
00690                  
00691      }
00692 
00693 
00699     bool handle_axis_mirror_step( Particle<PP> &particle, const PP &x1, PP &x2 ) {
00700 
00701         // Get acceleration at x2
00702         double dxdt[5];
00703         PP::get_derivatives( x2[0], &x2[1], dxdt, (void *)&_pidata );
00704 
00705         // Calculate crossover point assuming zero acceleration in
00706         // r-direction and constant acceleration in x-direction
00707         double dt = -x2[3]/x2[4];
00708         PP xc;
00709         xc[0] = x2[0]+dt;
00710         xc[1] = x2[1]+(x2[2]+0.5*dxdt[1]*dt)*dt;
00711         xc[2] = x2[2];
00712         xc[3] = x2[3]+x2[4]*dt;
00713         xc[4] = x2[4];
00714         xc[5] = x2[5];
00715 
00716         // Mirror x2 to x3
00717         PP x3 = 2*xc - x2;
00718         x3[3] *= -1.0;
00719         x3[4] *= -1.0;
00720         x3[5] *= -1.0;
00721 
00722 #ifdef DEBUG_PARTICLE_ITERATOR
00723         std::cout << "Particle mirror:\n";
00724         std::cout << "  x1: " << x1 << "\n";
00725         std::cout << "  x2: " << x2 << "\n";
00726         std::cout << "  xc: " << xc << "\n";
00727         std::cout << "  x3: " << x3 << "\n";
00728 #endif
00729         
00730         // Handle step with linear interpolation to avoid going to r<=0
00731         if( !handle_trajectory( particle, x2, x3, true, false ) )
00732             return( false ); // Particle done
00733 
00734         // Save trajectory calculation points
00735         _traj.push_back( x2 );
00736         _traj.push_back( xc );
00737         xc[4] *= -1.0;
00738         xc[5] *= -1.0;
00739         _traj.push_back( xc );
00740         
00741         // Next step not a continuation of previous one, reset
00742         // integrator
00743         gsl_odeiv_step_reset( _step );
00744         gsl_odeiv_evolve_reset( _evolve );
00745 
00746         // Continue iteration at mirrored point
00747         x2 = x3;
00748         return( true );
00749     }
00750     
00761     bool check_particle_definition( PP &x ) {
00762 
00763 #ifdef DEBUG_PARTICLE_ITERATOR
00764         std::cout << "Particle defined at:\n";
00765         std::cout << "  x = " << x << "\n";
00766 #endif
00767 
00768         // Check if inside solids or outside simulation geometry box.
00769         if( _pidata._geom->inside( x.location() ) )
00770             return( false );
00771 
00772         // Check if particle on simulation geometry border and directed outwards
00773         /*
00774         for( size_t a = 0; a < PP::dim(); a++ ) {
00775             if( x[2*a+1] == _pidata._geom->origo(a) && x[2*a+2] < 0.0 ) {
00776                 if( _mirror[2*a] ) {
00777                     x[2*a+2] *= -1.0;
00778 #ifdef DEBUG_PARTICLE_ITERATOR
00779         std::cout << "Mirroring to:\n";
00780         std::cout << "  x = " << x << "\n";
00781 #endif
00782                 } else {
00783                     return( false );
00784                 }
00785 
00786             } else if( x[2*a+1] == _pidata._geom->max(a) & x[2*a+2] > 0.0 ) {
00787                 if( _mirror[2*a+1] ) {
00788                     x[2*a+2] *= -1.0;
00789 #ifdef DEBUG_PARTICLE_ITERATOR
00790         std::cout << "Mirroring to:\n";
00791         std::cout << "  x = " << x << "\n";
00792 #endif
00793                 } else {
00794                     return( false );
00795                 }
00796             }
00797         }
00798 
00799 #ifdef DEBUG_PARTICLE_ITERATOR
00800         std::cout << "Definition ok\n";
00801 #endif
00802 
00803         */
00804         return( true );
00805     }
00806     
00807     double calculate_dt( const PP &x, const double *dxdt ) {
00808 
00809         double spd = 0.0, acc = 0.0;
00810 
00811         for( size_t a = 0; a < (PP::size()-1)/2; a++ ) {
00812             //std::cout << "spd += " << dxdt[2*a]*dxdt[2*a] << "\n";
00813             spd += dxdt[2*a]*dxdt[2*a];
00814             //std::cout << "acc += " << dxdt[2*a+1]*dxdt[2*a+1] << "\n";
00815             acc += dxdt[2*a+1]*dxdt[2*a+1];
00816         }
00817         if( _pidata._geom->geom_mode() == MODE_CYL ) {
00818             //std::cout << "MODE_CYL\n";
00819             //std::cout << "spd += " << x[3]*x[3]*x[5]*x[5] << "\n";
00820             spd += x[3]*x[3]*x[5]*x[5];
00821             //std::cout << "acc += " << x[3]*x[3]*dxdt[4]*dxdt[4] << "\n";
00822             acc += x[3]*x[3]*dxdt[4]*dxdt[4];
00823         }
00824         //std::cout << "spd = " << sqrt(spd) << "\n";
00825         //std::cout << "acc = " << sqrt(acc) << "\n";
00826         spd = _pidata._geom->h() / sqrt(spd);
00827         acc = sqrt( 2.0*_pidata._geom->h() / sqrt(acc) );
00828 
00829         return( spd < acc ? spd : acc );
00830     }
00831 
00832 public:
00833 
00860     ParticleIterator( particle_iterator_type_e type, double epsabs, double epsrel, 
00861                       bool polyint, uint32_t maxsteps, double maxt, 
00862                       uint32_t trajdiv, bool mirror[6], ScalarField *scharge, 
00863                       pthread_mutex_t *scharge_mutex,
00864                       const VectorField *efield, const VectorField *bfield, 
00865                       const Geometry *geom ) 
00866         : _type(type), _polyint(polyint), _epsabs(epsabs), _epsrel(epsrel), _maxsteps(maxsteps), _maxt(maxt), 
00867           _trajdiv(trajdiv), _pidata(scharge,efield,bfield,geom), 
00868           _thand_cb(0), _tend_cb(0), _bsup_cb(0), _pdb(0), _scharge_mutex(scharge_mutex), 
00869           _stat(geom->number_of_boundaries()) {
00870         
00871         // Initialize mirroring
00872         _mirror[0] = mirror[0];
00873         _mirror[1] = mirror[1];
00874         _mirror[2] = mirror[2];
00875         _mirror[3] = mirror[3];
00876         _mirror[4] = mirror[4];
00877         _mirror[5] = mirror[5];
00878 
00879         // Initialize system of ordinary differential equations (ODE)
00880         _system.jacobian  = NULL;
00881         _system.params    = (void *)&_pidata;
00882         _system.function  = PP::get_derivatives;
00883         _system.dimension = PP::size()-1; // Time is not part of differential equation dimensions
00884 
00885         // Make scale
00886         // 2D:  x vx y vy
00887         // Cyl: x vx r vr omega
00888         // 3D:  x vx y vy z vz
00889         double scale_abs[PP::size()-1];
00890         for( uint32_t a = 0; a < (uint32_t)PP::size()-2; a+=2 ) {
00891             scale_abs[a+0] = 1.0;
00892             scale_abs[a+1] = 1.0e6;
00893         }
00894         if( _pidata._geom->geom_mode() == MODE_CYL )
00895             scale_abs[4] = 1.0;
00896 
00897         // Initialize ODE solver
00898         _step    = gsl_odeiv_step_alloc( gsl_odeiv_step_rkck, _system.dimension );
00899         //_control = gsl_odeiv_control_standard_new( _epsabs, _epsrel, 1.0, 1.0 );
00900         _control = gsl_odeiv_control_scaled_new( _epsabs, _epsrel, 1.0, 1.0, scale_abs, PP::size()-1 );
00901         _evolve  = gsl_odeiv_evolve_alloc( _system.dimension );
00902     }
00903 
00904 
00907     ~ParticleIterator() {
00908         gsl_odeiv_evolve_free( _evolve );
00909         gsl_odeiv_control_free( _control );
00910         gsl_odeiv_step_free( _step );
00911     }
00912 
00913 
00916     void set_trajectory_handler_callback( const TrajectoryHandlerCallback *thand_cb ) {
00917         _thand_cb = thand_cb;
00918     }
00919 
00920 
00923     void set_trajectory_end_callback( const TrajectoryEndCallback *tend_cb, ParticleDataBase *pdb ) {
00924         _tend_cb = tend_cb;
00925         _pdb = pdb;
00926     }
00927 
00928 
00931     void set_bfield_suppression_callback( const CallbackFunctorD_V *bsup_cb ) {
00932         _pidata.set_bfield_suppression_callback( bsup_cb );
00933     }
00934 
00937     const ParticleStatistics &get_statistics( void ) const {
00938         return( _stat );
00939     }
00940 
00941     
00950     void operator()( Particle<PP> *particle, uint32_t pi ) {
00951 
00952         // Check particle status
00953         if( particle->get_status() != PARTICLE_OK )
00954             return;
00955 
00956         // Copy starting point to x and 
00957         PP x = particle->x();
00958 
00959         // Check particle definition
00960         if( !check_particle_definition( x ) ) {
00961             particle->set_status( PARTICLE_BADDEF );
00962             _stat.inc_end_baddef();
00963             return;
00964         }
00965         particle->x() = x;
00966 
00967         // Reset trajectory and save first trajectory point.
00968         _traj.clear();
00969         _traj.push_back( x );
00970 #ifdef DEBUG_PARTICLE_ITERATOR
00971         std::cout << x[0] << " " 
00972                   << x[1] << " " 
00973                   << x[2] << " " 
00974                   << x[3] << " " 
00975                   << x[4] << "\n";
00976 #endif
00977         _pidata._qm = particle->qm();
00978         _xi = x;
00979 
00980         // Reset integrator
00981         gsl_odeiv_step_reset( _step );
00982         gsl_odeiv_evolve_reset( _evolve );
00983         
00984         // Make initial guess for step size
00985         //std::cout << "Guess dt ------------------------------------------------\n";
00986         double dxdt[PP::size()-1];
00987         PP::get_derivatives( 0.0, &x[1], dxdt, (void *)&_pidata );
00988         double dt = calculate_dt( x, dxdt );
00989 
00990 #ifdef DEBUG_PARTICLE_ITERATOR
00991         std::cout << "dxdt = ";
00992         for( size_t a = 0; a < PP::size()-1; a++ )
00993             std::cout  << dxdt[a] << " ";
00994         std::cout << "\n";
00995         std::cout << "dt = " << dt << "\n";
00996         std::cout << "*** Starting iteration\n";
00997 #endif
00998         
00999         // Iterate ODEs until maximum steps are done, time is used 
01000         // or particle collides.
01001         PP x2;
01002         size_t nstp = 0; // Steps taken
01003         while( nstp < _maxsteps && x[0] < _maxt ) {
01004 
01005 #ifdef DEBUG_PARTICLE_ITERATOR
01006             std::cout << "\n*** Step ***\n";
01007             std::cout << "  x  = " << x2 << "\n";
01008             std::cout << "  dt = " << dt << " (proposed)\n";
01009 #endif
01010             
01011             // Take a step.
01012             x2 = x;
01013 
01014             while( true ) {
01015                 int retval = gsl_odeiv_evolve_apply( _evolve, _control, _step, &_system, 
01016                                                      &x2[0], _maxt, &dt, &x2[1] );
01017                 if( retval == IBSIMU_DERIV_ERROR ) {
01018 #ifdef DEBUG_PARTICLE_ITERATOR
01019                     std::cout << "Step rejected\n";
01020                     std::cout << "  x2 = " << x2 << "\n";
01021                     std::cout << "  dt = " << dt << "\n";
01022 #endif
01023                     x2[0] = x[0]; // Reset time (this shouldn't be necessary - there 
01024                                   // is a bug in GSL-1.12, report has been sent)
01025                     dt *= 0.5;
01026                     if( dt == 0.0 )
01027                         throw( Error( ERROR_LOCATION, "too small step size" ) );
01028                     //nstp++;
01029                     continue;
01030                 } else if( retval == GSL_SUCCESS ) {
01031                     break;
01032                 } else {
01033                     throw( Error( ERROR_LOCATION, "gsl_odeiv_evolve_apply failed" ) );
01034                 }
01035             }
01036             
01037             // Check step count number and step size validity
01038             if( nstp >= _maxsteps )
01039                 break;
01040             if( x2[0] == x[0] )
01041                 throw( Error( ERROR_LOCATION, "too small step size" ) );
01042 
01043 #ifdef DEBUG_PARTICLE_ITERATOR
01044             std::cout << "Step accepted from x1 to x2:\n";
01045             std::cout << "  dt = " << dt << " (taken)\n";
01046             std::cout << "  x1 = " << x << "\n";
01047             std::cout << "  x2 = " << x2 << "\n";
01048 #endif
01049 
01050             // Handle collisions and space charge of step.
01051             if( !handle_trajectory( *particle, x, x2, false, nstp == 0 ) ) {
01052                 x = x2;
01053                 break; // Particle done
01054             }
01055 
01056             // Check if particle mirroring is required to avoid 
01057             // singularity at symmetry axis.
01058             if( axis_mirror_required( x2 ) ) {
01059                 if( !handle_axis_mirror_step( *particle, x, x2 ) )
01060                     break; // Particle done
01061             }
01062 
01063             // Propagate coordinates
01064             x = x2;
01065 
01066             // Save trajectory point
01067             _traj.push_back( x2 );
01068             
01069             // Increase step count.
01070             nstp++;
01071         }
01072 
01073 #ifdef DEBUG_PARTICLE_ITERATOR
01074         std::cout << "\n*** Done stepping ***\n";
01075 #endif
01076 
01077         // Check if step count or time limited 
01078         if( nstp == _maxsteps ) {
01079             particle->set_status( PARTICLE_NSTP );
01080             _stat.inc_end_step();
01081         } else if( x[0] >= _maxt ) {
01082             particle->set_status( PARTICLE_TIME );
01083             _stat.inc_end_time();
01084         }
01085 
01086         // Save step count
01087         _stat.inc_sum_steps( nstp );
01088 
01089         // Save trajectory of current particle
01090         if( _trajdiv != 0 && pi % _trajdiv == 0 )
01091             particle->copy_trajectory( _traj );
01092 
01093         // Save last particle location
01094         particle->x() = x;
01095 
01096         // Call trajectory end callback
01097         if( _tend_cb )
01098             (*_tend_cb)( particle, _pdb );
01099     }
01100 
01101 };
01102 
01103 
01104 #endif


Reference manual for Ion Beam Simulator 1.0.4dev
Generated by Doxygen 1.7.1 on Wed May 18 2011 23:03:48.