43 #ifndef PARTICLEITERATOR_HPP
44 #define PARTICLEITERATOR_HPP 1
51 #include <gsl/gsl_odeiv.h>
52 #include <gsl/gsl_poly.h>
71 #ifdef DEBUG_PARTICLE_ITERATOR
72 #define DEBUG_MESSAGE(x) ibsimu.message(MSG_DEBUG_GENERAL,1) << x
73 #define DEBUG_INC_INDENT() ibsimu.inc_indent()
74 #define DEBUG_DEC_INDENT() ibsimu.dec_indent()
76 #define DEBUG_MESSAGE(x) do {} while(0)
77 #define DEBUG_INC_INDENT() do {} while(0)
78 #define DEBUG_DEC_INDENT() do {} while(0)
82 #define COLLISION_EPS 1.0e-6
88 PARTICLE_ITERATOR_ADAPTIVE = 0,
89 PARTICLE_ITERATOR_FIXED_STEP_LEN
121 return(
_x[0] < cd.
_x[0] );
133 const PP &x1,
const PP &x2 ) {
135 DEBUG_MESSAGE(
"Building coldata using linear interpolation\n" );
140 for(
size_t a = 0; a < PP::dim(); a++ ) {
142 int a1 = (int)floor( (x1[2*a+1]-mesh.
origo(a))/mesh.
h() );
143 int a2 = (int)floor( (x2[2*a+1]-mesh.
origo(a))/mesh.
h() );
150 for(
int b = a1+1; b <= a2; b++ ) {
153 double K = (b*mesh.
h() + mesh.
origo(a) - x1[2*a+1]) /
154 (x2[2*a+1] - x1[2*a+1]);
155 if( K < 0.0 ) K = 0.0;
156 else if( K > 1.0 ) K = 1.0;
158 DEBUG_MESSAGE(
"Adding point " << x1 + (x2-x1)*K <<
"\n" );
160 if( x2[2*a+1] > x1[2*a+1] )
161 coldata.push_back(
ColData( x1 + (x2-x1)*K, a+1 ) );
163 coldata.push_back(
ColData( x1 + (x2-x1)*K, -a-1 ) );
168 sort( coldata.begin(), coldata.end() );
171 DEBUG_MESSAGE(
"Coldata built\n" );
183 const PP &x1,
const PP &x2 ) {
185 DEBUG_MESSAGE(
"Building coldata using polynomial interpolation\n" );
192 for(
size_t a = 0; a < PP::dim(); a++ ) {
194 x1[2*a+1], x1[2*a+2],
195 x2[2*a+1], x2[2*a+2] );
196 DEBUG_MESSAGE(
"Trajectory polynomial " << a <<
" order = "
197 << traj[a].get_representation_order() <<
"\n" );
201 for(
size_t a = 0; a < PP::dim(); a++ ) {
204 int i = (int)floor( (x1[2*a+1]-mesh.
origo(a))/mesh.
h() );
207 for(
int dj = -1; dj <= 1; dj += 2 ) {
216 double val = mesh.
origo(a) + mesh.
h() * j;
217 if( val < mesh.
origo(a)-mesh.
h() )
219 else if( val > mesh.
max(a)+mesh.
h() )
222 DEBUG_MESSAGE(
"Searching intersections at coord(" << a <<
") = " << val <<
"\n" );
224 Kcount = traj[a].
solve( K, val );
229 DEBUG_MESSAGE(
"Found " << Kcount <<
" valid roots\n" );
231 for(
int b = 0; b < Kcount; b++ ) {
234 xcol(0) = x1[0] + K[b]*(x2[0]-x1[0]);
235 for(
size_t c = 0; c < PP::dim(); c++ ) {
236 traj[c].
coord( x, v, K[b] );
244 xcol[5] = x1[5] + K[b]*(x2[5]-x1[5]);
246 DEBUG_MESSAGE(
"K = " << K[b] <<
"\n" );
247 DEBUG_MESSAGE(
"Adding point " << xcol <<
"\n" );
249 if( xcol[2*a+2] >= 0.0 )
250 coldata.push_back(
ColData( xcol, a+1 ) );
252 coldata.push_back(
ColData( xcol, -a-1 ) );
262 sort( coldata.begin(), coldata.end() );
267 DEBUG_MESSAGE(
"Coldata built\n" );
282 gsl_odeiv_system _system;
283 gsl_odeiv_step *_step;
284 gsl_odeiv_control *_control;
285 gsl_odeiv_evolve *_evolve;
299 bool _surface_collision;
307 pthread_mutex_t *_scharge_mutex;
311 std::vector<PP> _traj;
312 std::vector<ColData<PP> > _coldata;
322 void save_trajectory_point( PP x ) {
325 _traj.push_back( x );
326 }
catch(
const std::bad_alloc & ) {
333 uint32_t get_solid(
int i,
int j,
int k ) {
335 if( PP::dim() == 2 ) {
337 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
338 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
339 return( node & SMESH_BOUNDARY_NUMBER_MASK );
341 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
342 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
343 return( node & SMESH_BOUNDARY_NUMBER_MASK );
345 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
346 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
347 return( node & SMESH_BOUNDARY_NUMBER_MASK );
349 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
350 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
351 return( node & SMESH_BOUNDARY_NUMBER_MASK );
354 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
355 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
356 return( node & SMESH_BOUNDARY_NUMBER_MASK );
358 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
359 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
360 return( node & SMESH_BOUNDARY_NUMBER_MASK );
362 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
363 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
364 return( node & SMESH_BOUNDARY_NUMBER_MASK );
365 node = _pidata.
_geom->
mesh( i+1, j+1, k );
366 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
367 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
368 return( node & SMESH_BOUNDARY_NUMBER_MASK );
370 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
371 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
372 return( node & SMESH_BOUNDARY_NUMBER_MASK );
373 node = _pidata.
_geom->
mesh( i+1, j, k+1 );
374 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
375 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
376 return( node & SMESH_BOUNDARY_NUMBER_MASK );
377 node = _pidata.
_geom->
mesh( i, j+1, k+1 );
378 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
379 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
380 return( node & SMESH_BOUNDARY_NUMBER_MASK );
381 node = _pidata.
_geom->
mesh( i+1, j+1, k+1 );
382 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
383 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
384 return( node & SMESH_BOUNDARY_NUMBER_MASK );
394 bool check_collision_surface(
Particle<PP> &particle,
const PP &x1,
const PP &x2,
395 PP &status_x,
const int32_t i[3] ) {
397 DEBUG_MESSAGE(
"Checking collisions with solids - surface check\n" );
402 else if( i[0] >= (int32_t)_pidata.
_geom->
size(0)-1 )
406 else if( i[1] >= (int32_t)_pidata.
_geom->
size(1)-1 )
410 else if( i[2] >= (int32_t)_pidata.
_geom->
size(2)-1 )
413 Vec3D v1 = x1.location();
414 Vec3D v2 = x2.location();
416 DEBUG_MESSAGE(
"v1 = " << v1 <<
"\n" );
417 DEBUG_MESSAGE(
"v2 = " << v2 <<
"\n" );
422 DEBUG_MESSAGE(
"tric = " << tric <<
"\n" );
425 for( int32_t a = 0; a < tric; a++ ) {
431 DEBUG_MESSAGE(
"a = " << a <<
"\n" );
432 DEBUG_MESSAGE(
"tri[" << a <<
"][0] = " << va <<
"\n" );
433 DEBUG_MESSAGE(
"tri[" << a <<
"][1] = " << vb <<
"\n" );
434 DEBUG_MESSAGE(
"tri[" << a <<
"][2] = " << vc <<
"\n" );
438 Mat3D m( v2[0]-v1[0], -vb[0]+va[0], -vc[0]+va[0],
439 v2[1]-v1[1], -vb[1]+va[1], -vc[1]+va[1],
440 v2[2]-v1[2], -vb[2]+va[2], -vc[2]+va[2] );
445 Vec3D off( -v1[0]+va[0], -v1[1]+va[1], -v1[2]+va[2] );
447 double K3 = K[1]+K[2];
448 DEBUG_MESSAGE(
"K = " << K <<
"\n" );
453 if( K[0] > -COLLISION_EPS && K[0] < 1.0+COLLISION_EPS &&
454 K[1] > -COLLISION_EPS && K[1] < 1.0+COLLISION_EPS &&
455 K[2] > -COLLISION_EPS && K[2] < 1.0+COLLISION_EPS &&
456 K3 > -COLLISION_EPS && K3 < 1.0+COLLISION_EPS ) {
458 DEBUG_MESSAGE(
"Intersection found\n" );
461 for( uint32_t b = 0; b < PP::size(); b++ )
462 status_x[b] = x1[b] + K[0]*(x2[b]-x1[b]);
466 for( int32_t b = _traj.size()-1; b > 0; b-- ) {
467 if( _traj[b][0] > status_x[0] )
475 uint32_t solid = get_solid( i[0], i[1], i[2] );
476 _stat.add_bound_collision( solid, particle.
IQ() );
479 (*_tsur_cb)( &particle, &status_x, ptr+a, K[1], K[2] );
481 DEBUG_MESSAGE(
"Solid collision detected\n" );
488 DEBUG_MESSAGE(
"No collisions\n" );
502 bool check_collision_solid(
Particle<PP> &particle,
const PP &x1,
const PP &x2,
505 DEBUG_MESSAGE(
"Checking collisions with solids - inside check\n" );
509 Vec3D v2 = x2.location();
512 DEBUG_MESSAGE(
"No collisions\n" );
517 Vec3D v1 = x1.location();
521 for(
size_t a = 0; a < PP::size(); a++ )
522 status_x[a] = x2[a] + K*(x1[a]-x2[a]);
525 for(
size_t a = _traj.size()-1; a > 0; a-- ) {
526 if( _traj[a][0] > status_x[0] )
537 _stat.add_bound_collision( bound, particle.
IQ() );
539 DEBUG_MESSAGE(
"Solid collision detected\n" );
549 bool check_collision(
Particle<PP> &particle,
const PP &x1,
const PP &x2,
550 PP &status_x,
const int i[3] ) {
552 if( _surface_collision )
553 return( check_collision_surface( particle, x1, x2, status_x, i ) );
554 return( check_collision_solid( particle, x1, x2, status_x ) );
565 void handle_mirror(
size_t c,
int i[3],
size_t a,
int border, PP &x2 ) {
567 DEBUG_MESSAGE(
"Mirror trajectory\n" );
579 DEBUG_MESSAGE(
"xmirror = " << xmirror <<
"\n" );
580 DEBUG_MESSAGE(
"i = (" << i[0] <<
", " << i[1] <<
", " << i[2] <<
")\n" );
581 DEBUG_MESSAGE(
"xi = " << _xi <<
"\n" );
584 bool caught_at_boundary =
false;
585 if( _coldata[c]._dir == border*((
int)a+1) &&
586 ( i[a] == 0 || i[a] == (
int)_pidata.
_geom->
size(a)-2 ) ) {
587 caught_at_boundary =
true;
588 DEBUG_MESSAGE(
"caught_at_boundary\n" );
592 if( caught_at_boundary ) {
593 save_trajectory_point( _coldata[c]._x );
595 for(
int b = _traj.size()-1; b > 0; b-- ) {
596 if( _traj[b][0] >= _xi[0] ) {
598 DEBUG_MESSAGE(
"mirroring traj[" << b <<
"] = " << _traj[b] <<
"\n" );
599 _traj[b][2*a+1] = 2.0*xmirror - _traj[b][2*a+1];
600 _traj[b][2*a+2] *= -1.0;
607 for(
size_t b = c; b < _coldata.size(); b++ ) {
608 if( (
size_t)abs(_coldata[b]._dir) == a+1 )
609 _coldata[b]._dir *= -1;
610 _coldata[b]._x[2*a+1] = 2.0*xmirror - _coldata[b]._x[2*a+1];
611 _coldata[b]._x[2*a+2] *= -1.0;
614 if( caught_at_boundary )
615 save_trajectory_point( _coldata[c]._x );
618 x2[2*a+1] = 2.0*xmirror - x2[2*a+1];
622 gsl_odeiv_step_reset( _step );
623 gsl_odeiv_evolve_reset( _evolve );
629 void handle_collision(
Particle<PP> &particle, uint32_t bound,
size_t c, PP &status_x ) {
631 DEBUG_MESSAGE(
"Handle collision\n" );
634 status_x = _coldata[c]._x;
636 _stat.add_bound_collision( bound, particle.
IQ() );
642 bool is_solid(
int i,
int j ) {
644 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
645 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
652 bool is_solid(
int i,
int j,
int k ) {
654 if( (node & SMESH_NODE_ID_MASK) == SMESH_NODE_ID_DIRICHLET &&
655 (node & SMESH_BOUNDARY_NUMBER_MASK) >= 7 )
668 bool handle_trajectory_advance(
Particle<PP> &particle,
size_t c,
int i[3], PP &x2 ) {
670 bool surface_collision =
false;
671 DEBUG_MESSAGE(
"Handle trajectory advance\n" );
675 if( PP::dim() == 2 ) {
676 if( _coldata[c]._dir == -1 ) {
677 if( (is_solid(i[0],i[1]) || is_solid(i[0], i[1]+1)) &&
678 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
679 surface_collision =
true;
681 }
else if( _coldata[c]._dir == +1 ) {
682 if( (is_solid(i[0]+1,i[1]) || is_solid(i[0]+1,i[1]+1)) &&
683 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
684 surface_collision =
true;
686 }
else if( _coldata[c]._dir == -2 ) {
687 if( (is_solid(i[0],i[1]) || is_solid(i[0]+1,i[1])) &&
688 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
689 surface_collision =
true;
692 if( (is_solid(i[0], i[1]+1) || is_solid(i[0]+1,i[1]+1)) &&
693 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
694 surface_collision =
true;
697 }
else if( PP::dim() == 3 ) {
698 if( _coldata[c]._dir == -1 ) {
699 if( (is_solid(i[0], i[1], i[2] ) ||
700 is_solid(i[0], i[1]+1,i[2] ) ||
701 is_solid(i[0], i[1], i[2]+1) ||
702 is_solid(i[0], i[1]+1,i[2]+1)) &&
703 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
704 surface_collision =
true;
706 }
else if( _coldata[c]._dir == +1 ) {
707 if( (is_solid(i[0]+1,i[1], i[2] ) ||
708 is_solid(i[0]+1,i[1]+1,i[2] ) ||
709 is_solid(i[0]+1,i[1], i[2]+1) ||
710 is_solid(i[0]+1,i[1]+1,i[2]+1)) &&
711 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
712 surface_collision =
true;
714 }
else if( _coldata[c]._dir == -2 ) {
715 if( (is_solid(i[0], i[1],i[2] ) ||
716 is_solid(i[0]+1,i[1],i[2] ) ||
717 is_solid(i[0], i[1],i[2]+1) ||
718 is_solid(i[0]+1,i[1],i[2]+1)) &&
719 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
720 surface_collision =
true;
722 }
else if( _coldata[c]._dir == +2 ) {
723 if( (is_solid(i[0], i[1]+1,i[2] ) ||
724 is_solid(i[0]+1,i[1]+1,i[2] ) ||
725 is_solid(i[0], i[1]+1,i[2]+1) ||
726 is_solid(i[0]+1,i[1]+1,i[2]+1)) &&
727 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
728 surface_collision =
true;
730 }
else if( _coldata[c]._dir == -3 ) {
731 if( (is_solid(i[0], i[1], i[2]) ||
732 is_solid(i[0]+1,i[1], i[2]) ||
733 is_solid(i[0], i[1]+1,i[2]) ||
734 is_solid(i[0]+1,i[1]+1,i[2])) &&
735 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
736 surface_collision =
true;
739 if( (is_solid(i[0], i[1], i[2]+1) ||
740 is_solid(i[0]+1,i[1], i[2]+1) ||
741 is_solid(i[0], i[1]+1,i[2]+1) ||
742 is_solid(i[0]+1,i[1]+1,i[2]+1)) &&
743 !check_collision( particle, _xi, _coldata[c]._x, x2, i ) )
744 surface_collision =
true;
751 if( surface_collision ) {
752 DEBUG_MESSAGE(
"Surface collision!\n" );
759 for(
size_t a = 0; a < PP::dim(); a++ ) {
762 DEBUG_MESSAGE(
"Boundary collision at boundary " << 2*a+0 <<
"\n" );
764 handle_mirror( c, i, a, -1, x2 );
766 handle_collision( particle, 1+2*a, c, x2 );
770 }
else if( i[a] >= (int32_t)(_pidata.
_geom->
size(a)-1) ) {
771 DEBUG_MESSAGE(
"Boundary collision at boundary " << 2*a+1 <<
"\n" );
773 handle_mirror( c, i, a, +1, x2 );
775 handle_collision( particle, 2+2*a, c, x2 );
782 DEBUG_MESSAGE(
"No collision.\n" );
792 bool limit_trajectory_advance(
const PP &x1, PP &x2 ) {
794 bool touched =
false;
795 for(
size_t a = 0; a < PP::dim(); a++ ) {
802 if( x2[2*a+1] < lim1 ) {
803 double K = (lim1 - x1[2*a+1]) / (x2[2*a+1] - x1[2*a+1]);
806 DEBUG_MESSAGE(
"Limiting step to " << x2 <<
"\n" );
807 }
else if(x2[2*a+1] > lim2 ) {
808 double K = (lim2 - x1[2*a+1]) / (x2[2*a+1] - x1[2*a+1]);
811 DEBUG_MESSAGE(
"Limiting step to " << x2 <<
"\n" );
822 void build_coldata(
bool force_linear,
const PP &x1,
const PP &x2 ) {
829 }
catch(
const std::bad_alloc & ) {
854 bool handle_trajectory(
Particle<PP> &particle,
const PP &x1, PP &x2,
855 bool force_linear,
bool first_step ) {
857 DEBUG_MESSAGE(
"Handle trajectory from x1 to x2:\n" <<
858 " x1 = " << x1 <<
"\n" <<
859 " x2 = " << x2 <<
"\n" );
864 if( limit_trajectory_advance( x1, x2 ) )
867 build_coldata( force_linear, x1, x2 );
874 if( _coldata.size() == 0 ) {
875 DEBUG_MESSAGE(
"No coldata\n" );
881 int i[3] = {0, 0, 0};
882 for(
size_t cdir = 0; cdir < PP::dim(); cdir++ )
886 DEBUG_MESSAGE(
"Process coldata points:\n" );
888 for(
size_t a = 0; a < _coldata.size(); a++ ) {
891 save_trajectory_point( _coldata[a]._x );
893 DEBUG_MESSAGE(
"Coldata " << a <<
"\n" <<
894 " x = " << _coldata[a]._x <<
"\n" <<
895 " i = (" << std::setw(3) << i[0] <<
", "
896 << std::setw(3) << i[1] <<
", "
897 << std::setw(3) << i[2] <<
")\n" <<
898 " dir = " << _coldata[a]._dir <<
"\n" );
902 _cdpast.push( _coldata[a]._x );
903 scharge_add_from_trajectory_linear( *_pidata.
_scharge, _scharge_mutex, particle.
IQ(),
904 _coldata[a]._dir, _cdpast, i );
909 handle_trajectory_advance( particle, a, i, x2 );
913 _xi, _coldata[a]._x );
918 (*_thand_cb)( &particle, &_coldata[a]._x, &x2 );
921 if( particle.get_status() != PARTICLE_OK ) {
922 save_trajectory_point( x2 );
925 DEBUG_MESSAGE(
"Interrupting coldata processing\n" );
931 _xi = _coldata[a]._x;
936 DEBUG_MESSAGE(
"Coldata done\n" );
944 bool axis_mirror_required(
const PP &x2 ) {
947 x2[3] <= 0.01*_pidata.
_geom->
h() &&
948 x2[3]*fabs(x2[5]) <= 1.0e-9*fabs(x2[4]) );
958 bool handle_axis_mirror_step(
Particle<PP> &particle,
const PP &x1, PP &x2 ) {
962 PP::get_derivatives( x2[0], &x2[1], dxdt, (
void *)&_pidata );
966 double dt = -x2[3]/x2[4];
970 xc[1] = x2[1]+(x2[2]+0.5*dxdt[1]*dt)*dt;
972 xc[3] = x2[3]+x2[4]*dt;
982 DEBUG_MESSAGE(
"Particle mirror:\n" <<
983 " x1: " << x1 <<
"\n" <<
984 " x2: " << x2 <<
"\n" <<
985 " xc: " << xc <<
"\n" <<
986 " x3: " << x3 <<
"\n" );
989 if( !handle_trajectory( particle, x2, x3,
true,
false ) )
993 save_trajectory_point( x2 );
994 save_trajectory_point( xc );
997 save_trajectory_point( xc );
1001 gsl_odeiv_step_reset( _step );
1002 gsl_odeiv_evolve_reset( _evolve );
1022 bool check_particle_definition( PP &x ) {
1024 DEBUG_MESSAGE(
"Particle defined at x = " << x <<
"\n" );
1028 for(
size_t a = 0; a < PP::size(); a++ ) {
1029 if( comp_isnan( x[a] ) ) {
1030 DEBUG_MESSAGE(
"Particle coordinate NaN\n" );
1037 if( _surface_collision ) {
1039 DEBUG_MESSAGE(
"Particle inside solid or outside simulation\n" );
1045 DEBUG_MESSAGE(
"Particle inside solid or outside simulation\n" );
1083 DEBUG_MESSAGE(
"Ok\n" );
1088 double calculate_dt(
const PP &x,
const double *dxdt ) {
1090 double spd = 0.0, acc = 0.0;
1092 for(
size_t a = 0; a < (PP::size()-1)/2; a++ ) {
1094 spd += dxdt[2*a]*dxdt[2*a];
1096 acc += dxdt[2*a+1]*dxdt[2*a+1];
1101 spd += x[3]*x[3]*x[5]*x[5];
1103 acc += x[3]*x[3]*dxdt[4]*dxdt[4];
1107 spd = _pidata.
_geom->
h() / sqrt(spd);
1108 acc = sqrt( 2.0*_pidata.
_geom->
h() / sqrt(acc) );
1110 return( spd < acc ? spd : acc );
1144 uint32_t maxsteps,
double maxt,
bool save_points,
1146 pthread_mutex_t *scharge_mutex,
1149 : _type(type), _intrp(intrp), _scharge_dep(scharge_dep), _epsabs(epsabs), _epsrel(epsrel),
1150 _maxsteps(maxsteps), _maxt(maxt), _save_points(save_points), _trajdiv(trajdiv),
1151 _surface_collision(false), _pidata(scharge,efield,bfield,geom),
1152 _thand_cb(0), _tend_cb(0), _tsur_cb(0), _bsup_cb(0), _pdb(0), _scharge_mutex(scharge_mutex),
1153 _stat(geom->number_of_boundaries()) {
1156 _mirror[0] = mirror[0];
1157 _mirror[1] = mirror[1];
1158 _mirror[2] = mirror[2];
1159 _mirror[3] = mirror[3];
1160 _mirror[4] = mirror[4];
1161 _mirror[5] = mirror[5];
1164 _system.jacobian = NULL;
1165 _system.params = (
void *)&_pidata;
1166 _system.function = PP::get_derivatives;
1167 _system.dimension = PP::size()-1;
1173 double scale_abs[PP::size()-1];
1174 for( uint32_t a = 0; a < (uint32_t)PP::size()-2; a+=2 ) {
1175 scale_abs[a+0] = 1.0;
1176 scale_abs[a+1] = 1.0e6;
1182 _step = gsl_odeiv_step_alloc( gsl_odeiv_step_rkck, _system.dimension );
1184 _control = gsl_odeiv_control_scaled_new( _epsabs, _epsrel, 1.0, 1.0, scale_abs, PP::size()-1 );
1185 _evolve = gsl_odeiv_evolve_alloc( _system.dimension );
1192 gsl_odeiv_evolve_free( _evolve );
1193 gsl_odeiv_control_free( _control );
1194 gsl_odeiv_step_free( _step );
1205 _surface_collision = surface_collision;
1212 _thand_cb = thand_cb;
1260 DEBUG_MESSAGE(
"Calculating particle " << pi <<
"\n" );
1264 if( particle->
get_status() != PARTICLE_OK ) {
1270 PP x = particle->
x();
1273 if( !check_particle_definition( x ) ) {
1275 _stat.inc_end_baddef();
1283 save_trajectory_point( x );
1284 _pidata.
_qm = particle->
qm();
1292 gsl_odeiv_step_reset( _step );
1293 gsl_odeiv_evolve_reset( _evolve );
1296 double dxdt[PP::size()-1];
1297 PP::get_derivatives( 0.0, &x[1], dxdt, (
void *)&_pidata );
1298 double dt = calculate_dt( x, dxdt );
1300 DEBUG_MESSAGE(
"Starting values for iteration:\n" <<
1302 for(
size_t a = 0; a < PP::size()-1; a++ )
1303 DEBUG_MESSAGE( dxdt[a] <<
" " );
1304 DEBUG_MESSAGE(
"\n" <<
1305 " dt = " << dt <<
"\n" );
1306 DEBUG_MESSAGE(
"Starting iteration\n" );
1312 while( nstp < _maxsteps && x[0] < _maxt ) {
1317 DEBUG_MESSAGE(
"\nStep *** *** *** ****\n" <<
1318 " x = " << x2 <<
"\n" <<
1319 " dt = " << dt <<
" (proposed)\n" );
1322 int retval = gsl_odeiv_evolve_apply( _evolve, _control, _step, &_system,
1323 &x2[0], _maxt, &dt, &x2[1] );
1324 if( retval == IBSIMU_DERIV_ERROR ) {
1325 DEBUG_MESSAGE(
"Step rejected\n" <<
1326 " x2 = " << x2 <<
"\n" <<
1327 " dt = " << dt <<
"\n" );
1335 }
else if( retval == GSL_SUCCESS ) {
1343 if( nstp >= _maxsteps )
1345 if( x2[0] == x[0] ) {
1347 ibsimu.
message( 1 ) <<
"Particle calculation failed. Coordinates:\n";
1348 for(
size_t a = 0; a < _traj.size(); a++ )
1356 DEBUG_MESSAGE(
"Step accepted from x1 to x2:\n" <<
1357 " x1 = " << x <<
"\n" <<
1358 " x2 = " << x2 <<
"\n" );
1361 if( !handle_trajectory( *particle, x, x2,
false, nstp == 0 ) ) {
1368 if( axis_mirror_required( x2 ) ) {
1369 if( !handle_axis_mirror_step( *particle, x, x2 ) )
1377 save_trajectory_point( x2 );
1380 DEBUG_MESSAGE(
"Done iterating\n" );
1383 if( nstp == _maxsteps ) {
1385 _stat.inc_end_step();
1386 }
else if( x[0] >= _maxt ) {
1388 _stat.inc_end_time();
1392 _stat.inc_sum_steps( nstp );
1395 if( _trajdiv != 0 && pi % _trajdiv == 0 )
1403 (*_tend_cb)( particle, _pdb );
First-in first-out container with cyclic memory.
Definition: callback.hpp:61
Mesh intersection (collision) coordinate data
Definition: particleiterator.hpp:102
static void build_coldata_linear(std::vector< ColData > &coldata, const Mesh &mesh, const PP &x1, const PP &x2)
Find mesh intersections of linearly interpolated particle trajectory segment.
Definition: particleiterator.hpp:132
bool operator<(const ColData &cd) const
Compare coldata entry times.
Definition: particleiterator.hpp:120
int _dir
Direction of particle at intersection. i: -1/+1, j: -2/+2, k: -3:/+3.
Definition: particleiterator.hpp:105
static void build_coldata_poly(std::vector< ColData > &coldata, const Mesh &mesh, const PP &x1, const PP &x2)
Find mesh intersections of polynomially interpolated particle trajectory segment.
Definition: particleiterator.hpp:182
PP _x
Mesh intersection coordinates.
Definition: particleiterator.hpp:104
ColData()
Default constructor.
Definition: particleiterator.hpp:110
ColData(PP x, int dir)
Constructor for collision at x into direction dir.
Definition: particleiterator.hpp:114
Error class for memory allocation errors.
Definition: error.hpp:196
Basic error class.
Definition: error.hpp:153
Geometry defining class.
Definition: geometry.hpp:180
uint32_t surface_trianglec(void) const
Return total surface triangle count.
Definition: geometry.hpp:528
const Vec3D & surface_vertex(int32_t a) const
Return reference to surface vertex a.
Definition: geometry.hpp:534
double bracket_surface(uint32_t n, const Vec3D &xin, const Vec3D &xout, Vec3D &xsurf) const
Find solid n surface location by bracketing.
Definition: geometry.cpp:431
bool surface_built(void) const
Is the solid surface representation built?
Definition: geometry.hpp:503
uint32_t inside(const Vec3D &x) const
Return if point is inside solids.
Definition: geometry.cpp:334
const uint32_t & mesh(int32_t i) const
Returns a const reference to solid mesh array.
Definition: geometry.hpp:399
uint32_t surface_inside(const Vec3D &x) const
Finds if point is inside surface triangulation.
Definition: geometry.cpp:2243
uint32_t mesh_check(int32_t i) const
Returns number from solid mesh array.
Definition: geometry.cpp:386
const VTriangle & surface_triangle(int32_t a) const
Return reference to surface triangle a.
Definition: geometry.hpp:550
uint32_t surface_triangle_ptr(int32_t i, int32_t j, int32_t k) const
Return index of first surface triangle at mesh cube (i,j,k).
Definition: geometry.hpp:556
std::ostream & message(message_type_e type, int32_t level)
Print message output.
Definition: ibsimu.cpp:111
Three-by-three matrix.
Definition: mat3d.hpp:58
double determinant(void) const
Return determinant of matrix.
Definition: mat3d.cpp:74
Mat3D inverse(void) const
Return inverse matrix.
Definition: mat3d.cpp:83
Scalar field class.
Definition: meshscalarfield.hpp:70
Mesh geometry definion.
Definition: mesh.hpp:68
double h(void) const
Returns mesh cell size.
Definition: mesh.hpp:146
Int3D size(void) const
Returns size array of geometry.
Definition: mesh.hpp:116
Vec3D max(void) const
Returns vector pointing to the last mesh point opposite of origo.
Definition: mesh.hpp:137
double div_h(void) const
Returns reciprocal of mesh cell size (1/h).
Definition: mesh.hpp:150
Vec3D origo(void) const
Returns origo vector of geometry.
Definition: mesh.hpp:128
geom_mode_e geom_mode(void) const
Returns geometry mode.
Definition: mesh.hpp:108
void set_status(particle_status_e status)
Set particle status.
Definition: particles.hpp:699
double IQ() const
Return current or charge carried by trajectory or particle cloud [A/C].
Definition: particles.hpp:706
particle_status_e get_status()
Return particle status.
Definition: particles.hpp:695
double qm() const
Return charge per mass ratio (q/m) [C/kg].
Definition: particles.hpp:718
Particle database base class.
Definition: particledatabase.hpp:191
Particle iterator class for continuous Vlasov-type iteration.
Definition: particleiterator.hpp:280
void set_relativistic(bool enable)
Set relativistic particle iteration.
Definition: particleiterator.hpp:1239
void operator()(Particle< PP > *particle, uint32_t pi)
Iterate a particle from start to end.
Definition: particleiterator.hpp:1258
void set_trajectory_surface_collision_callback(TrajectorySurfaceCollisionCallback *tsur_cb)
Set trajectory surface collision callback.
Definition: particleiterator.hpp:1226
void set_surface_collision(bool surface_collision)
Enable/disable surface collision model.
Definition: particleiterator.hpp:1200
void set_trajectory_end_callback(TrajectoryEndCallback *tend_cb, ParticleDataBase *pdb)
Set trajectory end callback.
Definition: particleiterator.hpp:1218
ParticleIterator(particle_iterator_type_e type, double epsabs, double epsrel, trajectory_interpolation_e intrp, scharge_deposition_e scharge_dep, uint32_t maxsteps, double maxt, bool save_points, uint32_t trajdiv, bool mirror[6], MeshScalarField *scharge, pthread_mutex_t *scharge_mutex, const VectorField *efield, const VectorField *bfield, const Geometry *geom)
Constructor for new particle iterator.
Definition: particleiterator.hpp:1142
void set_bfield_suppression_callback(const CallbackFunctorD_V *bsup_cb)
Set B-field potential dependent suppression callback.
Definition: particleiterator.hpp:1233
void set_trajectory_handler_callback(TrajectoryHandlerCallback *thand_cb)
Set trajectory handler callback.
Definition: particleiterator.hpp:1211
~ParticleIterator()
Destructor.
Definition: particleiterator.hpp:1191
const ParticleStatistics & get_statistics(void) const
Get particle iterator statistics.
Definition: particleiterator.hpp:1245
Particle iteration statistics.
Definition: particlestatistics.hpp:57
Particle class in some geometry.
Definition: particles.hpp:740
PP & x()
Return reference to coordinate data.
Definition: particles.hpp:798
void copy_trajectory(const std::vector< PP > &traj)
Define trajectory by copying.
Definition: particles.hpp:822
Trajectory end callback.
Definition: particledatabase.hpp:71
Trajectory handler callback.
Definition: particledatabase.hpp:58
Trajectory representation between two calculated points in 1d.
Definition: trajectory.hpp:65
void construct(double dt, double x1, double v1, double x2, double v2, trajectory_rep_e force=TRAJ_EMPTY)
Construct representation of trajectory from (x1,v1) to (x2,v2) in time dt.
Definition: trajectory.cpp:53
void coord(double &x, double &v, double K)
Calculate location x and velocity v at parametric time K.
Definition: trajectory.cpp:152
int solve(double K[3], double x, int extrapolate=0)
Solves for trajectory intersection with location.
Definition: trajectory.cpp:186
Trajectory surface collision callback.
Definition: particledatabase.hpp:86
Vertex-based triangle representation.
Definition: vtriangle.hpp:56
Three dimensional vector.
Definition: vec3d.hpp:58
Vector field.
Definition: vectorfield.hpp:56
std::string to_string(const T &t)
Function for converting a type to string.
Definition: error.hpp:62
#define ERROR_LOCATION
Macro for setting error location when throwing errors.
Definition: error.hpp:83
IBSimu ibsimu
Global instance of class IBSimu.
Definition: ibsimu.cpp:289
Ion Beam Simulator global settings.
Mesh based scalar fields.
particle_iterator_type_e
Particle iterator type.
Definition: particleiterator.hpp:87
Particle and particle point objects
void scharge_add_from_trajectory_pic(MeshScalarField &scharge, pthread_mutex_t *mutex, double I, const ParticleP2D &x1, const ParticleP2D &x2)
Function for adding charge to space charge density map from particle trajectory in 2d simulation.
Definition: scharge.cpp:171
Space charge deposition functions.
Job scheduler for parallel processing.
Temporary data bundle for particle iterators.
Definition: particles.hpp:928
double _qm
Precalculated q/m.
Definition: particles.hpp:933
void set_relativistic(bool enable)
Set relativistic particle iteration.
Definition: particles.hpp:950
MeshScalarField * _scharge
Space charge field or NULL.
Definition: particles.hpp:929
void set_bfield_suppression_callback(const CallbackFunctorD_V *bsup_cb)
Set B-field potential dependent suppression callback.
Definition: particles.hpp:944
const Geometry * _geom
Geometry.
Definition: particles.hpp:932
Trajectory interpolation solver.
trajectory_interpolation_e
Trajectory interpolation type.
Definition: types.hpp:153
@ TRAJECTORY_INTERPOLATION_POLYNOMIAL
Polynomial interpolation.
Definition: types.hpp:154
@ MODE_CYL
Cylindrically symmetric geometry.
Definition: types.hpp:62
@ MODE_2D
2D geometry
Definition: types.hpp:61
scharge_deposition_e
Space charge depostition type.
Definition: types.hpp:161
@ SCHARGE_DEPOSITION_LINEAR
Deposition to nodes as a linear function of distance to closet trajectory segment.
Definition: types.hpp:163
@ SCHARGE_DEPOSITION_PIC
Particle-in-cell type deposition to neighbouring nodes in each cell.
Definition: types.hpp:162