MPI-AMRVAC  3.0
The MPI - Adaptive Mesh Refinement - Versatile Advection Code
mod_particle_gca.t
Go to the documentation of this file.
1 !> Particle mover with Newtonian/relativistic Guiding Center Approximation (GCA)
2 !> By Jannis Teunissen, Bart Ripperda, Oliver Porth, and Fabio Bacchini (2016-2020)
5 
6  private
7 
8  !> Variable index for gradient B, with relativistic correction 1/kappa
9  !> where kappa = 1/sqrt(1 - E_perp^2/B^2)
10  integer, protected, allocatable :: grad_kappa_b(:)
11  !> Variable index for (B . grad)B (curvature B drift)
12  integer, protected, allocatable :: b_dot_grad_b(:)
13 
14  ! ExB related drifts (vE = ExB/B^2)
15  !> Variable index for curvature drift
16  integer, protected, allocatable :: ve_dot_grad_b(:)
17  !> Variable index for polarization drift
18  integer, protected, allocatable :: b_dot_grad_ve(:)
19  !> Variable index for polarization drift
20  integer, protected, allocatable :: ve_dot_grad_ve(:)
21 
22  public :: gca_init
23  public :: gca_create_particles
24 
25  ! Variables
26  public :: bp, ep, grad_kappa_b, b_dot_grad_b
28  public :: vp, jp
29 
30 contains
31 
32  subroutine gca_init()
34  integer :: idir, nwx
35 
36  if (physics_type/='mhd') call mpistop("GCA particles need magnetic field!")
37  if (ndir/=3) call mpistop("GCA particles need ndir=3!")
38 
39  nwx = 0
40  allocate(bp(ndir))
41  do idir = 1, ndir
42  nwx = nwx + 1
43  bp(idir) = nwx
44  end do
45  allocate(ep(ndir))
46  do idir = 1, ndir
47  nwx = nwx + 1
48  ep(idir) = nwx
49  end do
50  allocate(grad_kappa_b(ndir))
51  do idir = 1, ndir
52  nwx = nwx + 1
53  grad_kappa_b(idir) = nwx
54  end do
55  allocate(b_dot_grad_b(ndir))
56  do idir = 1, ndir
57  nwx = nwx + 1
58  b_dot_grad_b(idir) = nwx
59  end do
60  allocate(ve_dot_grad_b(ndir))
61  do idir = 1, ndir
62  nwx = nwx + 1
63  ve_dot_grad_b(idir) = nwx
64  end do
65  allocate(b_dot_grad_ve(ndir))
66  do idir = 1, ndir
67  nwx = nwx + 1
68  b_dot_grad_ve(idir) = nwx
69  end do
70  allocate(ve_dot_grad_ve(ndir))
71  do idir = 1, ndir
72  nwx = nwx + 1
73  ve_dot_grad_ve(idir) = nwx
74  end do
75  allocate(vp(ndir))
76  do idir = 1, ndir
77  nwx = nwx + 1
78  vp(idir) = nwx
79  end do
80  allocate(jp(ndir))
81  do idir = 1, ndir
82  nwx = nwx + 1
83  jp(idir) = nwx
84  end do
85  ngridvars=nwx
86 
88 
89  if (associated(particles_define_additional_gridvars)) then
91  end if
92 
94 
95  end subroutine gca_init
96 
97  subroutine gca_create_particles()
98  ! initialise the particles
101 
102  double precision :: b(ndir), u(ndir), magmom
103  double precision :: bnorm, lfac, vnorm, vperp, vpar
104  integer :: igrid, ipe_particle
105  integer :: n, idir, nparticles_local
106  double precision :: x(3, num_particles)
107  double precision :: v(3, num_particles)
108  double precision :: q(num_particles)
109  double precision :: m(num_particles)
110  double precision :: rrd(num_particles,ndir)
111  double precision :: defpayload(ndefpayload)
112  double precision :: usrpayload(nusrpayload)
113  logical :: follow(num_particles), check
114 
115  if (mype==0) then
116  if (.not. associated(usr_create_particles)) then
117  ! Randomly distributed
118  do idir=1,ndir
119  do n = 1, num_particles
120  rrd(n,idir) = rng%unif_01()
121  end do
122  end do
123  do n=1, num_particles
124  {^d&x(^d,n) = xprobmin^d + rrd(n+1,^d) * (xprobmax^d - xprobmin^d)\}
125  end do
126  else
127  call usr_create_particles(num_particles, x, v, q, m, follow)
128  end if
129  end if
130 
131  call mpi_bcast(x,3*num_particles,mpi_double_precision,0,icomm,ierrmpi)
132  call mpi_bcast(v,3*num_particles,mpi_double_precision,0,icomm,ierrmpi)
133  call mpi_bcast(q,num_particles,mpi_double_precision,0,icomm,ierrmpi)
134  call mpi_bcast(m,num_particles,mpi_double_precision,0,icomm,ierrmpi)
135  call mpi_bcast(follow,num_particles,mpi_logical,0,icomm,ierrmpi)
136 
137  nparticles_local = 0
138 
139  ! first find ipe and igrid responsible for particle
140  do n = 1, num_particles
141  call find_particle_ipe(x(:, n),igrid,ipe_particle)
142 
143  particle(n)%igrid = igrid
144  particle(n)%ipe = ipe_particle
145 
146  if(ipe_particle == mype) then
147  check = .true.
148 
149  ! Check for user-defined modifications or rejection conditions
150  if (associated(usr_check_particle)) call usr_check_particle(igrid, x(:,n), v(:,n), q(n), m(n), follow(n), check)
151  if (check) then
153  else
154  cycle
155  end if
156 
157  nparticles_local = nparticles_local + 1
158 
159  call get_lfac_from_velocity(v(:, n), lfac)
160 
161  allocate(particle(n)%self)
162  particle(n)%self%x = x(:, n)
163  particle(n)%self%q = q(n)
164  particle(n)%self%m = m(n)
165  particle(n)%self%follow = follow(n)
166  particle(n)%self%index = n
167  particle(n)%self%time = global_time
168  particle(n)%self%dt = 0.0d0
169 
170  call get_vec(bp, igrid, x(:, n), particle(n)%self%time, b)
171 
172  bnorm = norm2(b(:))
173  vnorm = norm2(v(:, n))
174  vpar = sum(v(:, n) * b/bnorm)
175  vperp = sqrt(vnorm**2 - vpar**2)
176 
177  ! The momentum vector u(1:3) is filled with the following components
178 
179  ! parallel momentum component (gamma v||)
180  particle(n)%self%u(1) = lfac * vpar
181 
182  ! Mr: the conserved magnetic moment
183  magmom = m(n) * (vperp * lfac)**2 / (2.0d0 * bnorm)
184  particle(n)%self%u(2) = magmom
185 
186  ! Lorentz factor
187  particle(n)%self%u(3) = lfac
188 
189  ! initialise payloads for GCA module
190  allocate(particle(n)%payload(npayload))
191  call gca_update_payload(igrid,ps(igrid)%w,pso(igrid)%w,ps(igrid)%x,x(:,n),particle(n)%self%u(:),q(n),m(n),defpayload,ndefpayload,0.d0)
192  particle(n)%payload(1:ndefpayload) = defpayload
193  if (associated(usr_update_payload)) then
194  call usr_update_payload(igrid,ps(igrid)%w,pso(igrid)%w,ps(igrid)%x,x(:,n),particle(n)%self%u(:),q(n),m(n),usrpayload,nusrpayload,0.d0)
195  particle(n)%payload(ndefpayload+1:npayload) = usrpayload
196  end if
197  end if
198  end do
199 
200  call mpi_allreduce(nparticles_local,nparticles,1,mpi_integer,mpi_sum,icomm,ierrmpi)
201 
202  end subroutine gca_create_particles
203 
204  subroutine gca_fill_gridvars
207  use mod_geometry
208 
209  integer :: igrid, iigrid, idir, idim
210  double precision, dimension(ixG^T,1:ndir) :: beta
211  double precision, dimension(ixG^T,1:nw) :: w,wold
212  double precision :: current(ixG^T,7-2*ndir:3)
213  integer :: idirmin
214  double precision, dimension(ixG^T,1:ndir) :: vE, bhat
215  double precision, dimension(ixG^T) :: kappa, kappa_B, absB, tmp
216 
217  call fill_gridvars_default()
218 
219  do iigrid=1,igridstail; igrid=igrids(iigrid);
220  w(ixg^t,1:nw) = ps(igrid)%w(ixg^t,1:nw)
221  call phys_to_primitive(ixg^ll,ixg^ll,w,ps(igrid)%x)
222  ! fill with velocity:
223  gridvars(igrid)%w(ixg^t,vp(:)) = w(ixg^t,iw_mom(:))
224 
225  ! grad(kappa B)
226  absb(ixg^t) = sqrt(sum(gridvars(igrid)%w(ixg^t,bp(:))**2,dim=ndim+1))
227  ve(ixg^t,1) = gridvars(igrid)%w(ixg^t,ep(2)) * gridvars(igrid)%w(ixg^t,bp(3)) &
228  - gridvars(igrid)%w(ixg^t,ep(3)) * gridvars(igrid)%w(ixg^t,bp(2))
229  ve(ixg^t,2) = gridvars(igrid)%w(ixg^t,ep(3)) * gridvars(igrid)%w(ixg^t,bp(1)) &
230  - gridvars(igrid)%w(ixg^t,ep(1)) * gridvars(igrid)%w(ixg^t,bp(3))
231  ve(ixg^t,3) = gridvars(igrid)%w(ixg^t,ep(1)) * gridvars(igrid)%w(ixg^t,bp(2)) &
232  - gridvars(igrid)%w(ixg^t,ep(2)) * gridvars(igrid)%w(ixg^t,bp(1))
233  do idir=1,ndir
234  where (absb(ixg^t) .gt. 0.d0)
235  ve(ixg^t,idir) = ve(ixg^t,idir) / absb(ixg^t)**2
236  elsewhere
237  ve(ixg^t,idir) = 0.d0
238  end where
239  end do
240  if (any(sum(ve(ixg^t,:)**2,dim=ndim+1) .ge. c_norm**2) .and. relativistic) then
241  call mpistop("GCA FILL GRIDVARS: vE>c! ABORTING...")
242  end if
243  if (any(ve .ne. ve)) then
244  call mpistop("GCA FILL GRIDVARS: NaNs IN vE! ABORTING...")
245  end if
246 
247  if (relativistic) then
248  kappa(ixg^t) = 1.d0/sqrt(1.0d0 - sum(ve(ixg^t,:)**2,dim=ndim+1)/c_norm**2)
249  else
250  kappa(ixg^t) = 1.d0
251  end if
252  kappa_b(ixg^t) = absb(ixg^t) / kappa(ixg^t)
253 
254  if (any(kappa_b .ne. kappa_b)) then
255  call mpistop("GCA FILL GRIDVARS: NaNs IN kappa_B! ABORTING...")
256  end if
257 
258  do idim=1,ndim
259  call gradient(kappa_b,ixg^ll,ixg^ll^lsub1,idim,tmp)
260  gridvars(igrid)%w(ixg^t,grad_kappa_b(idim)) = tmp(ixg^t)
261  end do
262 
263  ! bhat
264  do idir=1,ndir
265  where (absb(ixg^t) .gt. 0.d0)
266  bhat(ixg^t,idir) = gridvars(igrid)%w(ixg^t,bp(idir)) / absb(ixg^t)
267  elsewhere
268  bhat(ixg^t,idir) = 0.d0
269  end where
270  end do
271  if (any(bhat .ne. bhat)) then
272  call mpistop("GCA FILL GRIDVARS: NaNs IN bhat! ABORTING...")
273  end if
274 
275  do idir=1,ndir
276  ! (b dot grad) b and the other directional derivatives
277  do idim=1,ndim
278  call gradient(bhat(ixg^t,idir),ixg^ll,ixg^ll^lsub1,idim,tmp)
279  gridvars(igrid)%w(ixg^t,b_dot_grad_b(idir)) = gridvars(igrid)%w(ixg^t,b_dot_grad_b(idir)) &
280  + bhat(ixg^t,idim) * tmp(ixg^t)
281  gridvars(igrid)%w(ixg^t,ve_dot_grad_b(idir)) = gridvars(igrid)%w(ixg^t,ve_dot_grad_b(idir)) &
282  + ve(ixg^t,idim) * tmp(ixg^t)
283  call gradient(ve(ixg^t,idir),ixg^ll,ixg^ll^lsub1,idim,tmp)
284  gridvars(igrid)%w(ixg^t,b_dot_grad_ve(idir)) = gridvars(igrid)%w(ixg^t,b_dot_grad_ve(idir)) &
285  + bhat(ixg^t,idim) * tmp(ixg^t)
286  gridvars(igrid)%w(ixg^t,ve_dot_grad_ve(idir)) = gridvars(igrid)%w(ixg^t,ve_dot_grad_ve(idir)) &
287  + ve(ixg^t,idim) * tmp(ixg^t)
288  end do
289  end do
290 
291  if(time_advance) then
292  ! Fluid velocity
293  w(ixg^t,1:nw) = pso(igrid)%w(ixg^t,1:nw)
294  call phys_to_primitive(ixg^ll,ixg^ll,w,ps(igrid)%x)
295  gridvars(igrid)%wold(ixg^t,vp(:)) = w(ixg^t,iw_mom(:))
296 
297  ! grad(kappa B)
298  absb(ixg^t) = sqrt(sum(gridvars(igrid)%wold(ixg^t,bp(:))**2,dim=ndim+1))
299  ve(ixg^t,1) = gridvars(igrid)%wold(ixg^t,ep(2)) * gridvars(igrid)%wold(ixg^t,bp(3)) &
300  - gridvars(igrid)%wold(ixg^t,ep(3)) * gridvars(igrid)%wold(ixg^t,bp(2))
301  ve(ixg^t,2) = gridvars(igrid)%wold(ixg^t,ep(3)) * gridvars(igrid)%wold(ixg^t,bp(1)) &
302  - gridvars(igrid)%wold(ixg^t,ep(1)) * gridvars(igrid)%wold(ixg^t,bp(3))
303  ve(ixg^t,3) = gridvars(igrid)%wold(ixg^t,ep(1)) * gridvars(igrid)%wold(ixg^t,bp(2)) &
304  - gridvars(igrid)%wold(ixg^t,ep(2)) * gridvars(igrid)%wold(ixg^t,bp(1))
305  do idir=1,ndir
306  where (absb(ixg^t) .gt. 0.d0)
307  ve(ixg^t,idir) = ve(ixg^t,idir) / absb(ixg^t)**2
308  elsewhere
309  ve(ixg^t,idir) = 0.d0
310  end where
311  end do
312  if (any(sum(ve(ixg^t,:)**2,dim=ndim+1) .ge. c_norm**2) .and. relativistic) then
313  call mpistop("GCA FILL GRIDVARS: vE>c! ABORTING...")
314  end if
315  if (any(ve .ne. ve)) then
316  call mpistop("GCA FILL GRIDVARS: NaNs IN vE! ABORTING...")
317  end if
318 
319  if (relativistic) then
320  kappa(ixg^t) = 1.d0/sqrt(1.0d0 - sum(ve(ixg^t,:)**2,dim=ndim+1)/c_norm**2)
321  else
322  kappa(ixg^t) = 1.d0
323  end if
324  kappa_b(ixg^t) = absb(ixg^t) / kappa(ixg^t)
325  if (any(kappa_b .ne. kappa_b)) then
326  call mpistop("GCA FILL GRIDVARS: NaNs IN kappa_B! ABORTING...")
327  end if
328 
329  do idim=1,ndim
330  call gradient(kappa_b,ixg^ll,ixg^ll^lsub1,idim,tmp)
331  gridvars(igrid)%wold(ixg^t,grad_kappa_b(idim)) = tmp(ixg^t)
332  end do
333 
334  do idir=1,ndir
335  where (absb(ixg^t) .gt. 0.d0)
336  bhat(ixg^t,idir) = gridvars(igrid)%wold(ixg^t,bp(idir)) / absb(ixg^t)
337  elsewhere
338  bhat(ixg^t,idir) = 0.d0
339  end where
340  end do
341  if (any(bhat .ne. bhat)) then
342  call mpistop("GCA FILL GRIDVARS: NaNs IN bhat! ABORTING...")
343  end if
344 
345  do idir=1,ndir
346  ! (b dot grad) b and the other directional derivatives
347  do idim=1,ndim
348  call gradient(bhat(ixg^t,idir),ixg^ll,ixg^ll^lsub1,idim,tmp)
349  gridvars(igrid)%wold(ixg^t,b_dot_grad_b(idir)) = gridvars(igrid)%wold(ixg^t,b_dot_grad_b(idir)) &
350  + bhat(ixg^t,idim) * tmp(ixg^t)
351  gridvars(igrid)%wold(ixg^t,ve_dot_grad_b(idir)) = gridvars(igrid)%wold(ixg^t,ve_dot_grad_b(idir)) &
352  + ve(ixg^t,idim) * tmp(ixg^t)
353  call gradient(ve(ixg^t,idir),ixg^ll,ixg^ll^lsub1,idim,tmp)
354  gridvars(igrid)%wold(ixg^t,b_dot_grad_ve(idir)) = gridvars(igrid)%wold(ixg^t,b_dot_grad_ve(idir)) &
355  + bhat(ixg^t,idim) * tmp(ixg^t)
356  gridvars(igrid)%wold(ixg^t,ve_dot_grad_ve(idir)) = gridvars(igrid)%wold(ixg^t,ve_dot_grad_ve(idir)) &
357  + ve(ixg^t,idim) * tmp(ixg^t)
358  end do
359  end do
360  end if
361  end do
362 
363  end subroutine gca_fill_gridvars
364 
365  subroutine gca_integrate_particles(end_time)
366  use mod_odeint
369  double precision, intent(in) :: end_time
370 
371  double precision :: lfac, absS
372  double precision :: defpayload(ndefpayload)
373  double precision :: usrpayload(nusrpayload)
374  double precision :: dt_p, tloc, y(ndir+2),dydt(ndir+2),ytmp(ndir+2), euler_cfl, int_factor
375  double precision, dimension(1:ndir) :: x, vE, e, b, bhat, x_new, vfluid, current
376  double precision, dimension(1:ndir) :: drift1, drift2
377  double precision, dimension(1:ndir) :: drift3, drift4, drift5, drift6, drift7
378  double precision, dimension(1:ndir) :: bdotgradb, vEdotgradb, gradkappaB
379  double precision, dimension(1:ndir) :: bdotgradvE, vEdotgradvE
380  double precision, dimension(1:ndir) :: gradBdrift, reldrift, bdotgradbdrift
381  double precision, dimension(1:ndir) :: vEdotgradbdrift, bdotgradvEdrift
382  double precision, dimension(1:ndir) :: vEdotgradvEdrift
383  double precision :: kappa, Mr, upar, m, absb, gamma, q, mompar, vpar, vEabs
384  double precision :: gradBdrift_abs, reldrift_abs, epar
385  double precision :: bdotgradbdrift_abs, vEdotgradbdrift_abs
386  double precision :: bdotgradvEdrift_abs, vEdotgradvEdrift_abs
387  double precision :: momentumpar1, momentumpar2, momentumpar3, momentumpar4
388  ! Precision of time-integration:
389  double precision,parameter :: eps=1.0d-6
390  ! for odeint:
391  double precision :: h1, hmin, h_old
392  integer :: nok, nbad, ic1^D, ic2^D, ierror, nvar
393  integer :: ipart, iipart, seed, ic^D,igrid_particle, ipe_particle, ipe_working
394  logical :: int_choice
395  logical :: BC_applied
396 
397  nvar=ndir+2
398 
399  do iipart=1,nparticles_active_on_mype
400  ipart = particles_active_on_mype(iipart)
401  int_choice = .false.
402  dt_p = gca_get_particle_dt(particle(ipart), end_time)
403  particle(ipart)%self%dt = dt_p
404 
405  igrid_working = particle(ipart)%igrid
406  ipart_working = particle(ipart)%self%index
407  tloc = particle(ipart)%self%time
408  x(1:ndir) = particle(ipart)%self%x(1:ndir)
409 
410  ! Adaptive stepwidth RK4:
411  ! initial solution vector:
412  y(1:ndir) = x(1:ndir) ! position of guiding center
413  y(ndir+1) = particle(ipart)%self%u(1) ! parallel momentum component (gamma v||)
414  y(ndir+2) = particle(ipart)%self%u(2) ! conserved magnetic moment Mr
415  ! y(ndir+3) = particle(ipart)%self%u(3) ! Lorentz factor of particle
416 
417  ! we temporarily save the solution vector, to replace the one from the euler
418  ! timestep after euler integration
419  ytmp=y
420 
421  call derivs_gca(particle(ipart)%self%time,y,dydt)
422 
423  ! make an Euler step with the proposed timestep:
424  ! factor to ensure we capture all particles near the internal ghost cells.
425  ! Can be adjusted during a run, after an interpolation error.
426  euler_cfl=2.5d0
427 
428  ! new solution vector:
429  y(1:ndir+2) = y(1:ndir+2) + euler_cfl * dt_p * dydt(1:ndir+2)
430  particle(ipart)%self%x(1:ndir) = y(1:ndir) ! position of guiding center
431  particle(ipart)%self%u(1) = y(ndir+1) ! parallel momentum component(gamma v||)
432  particle(ipart)%self%u(2) = y(ndir+2) ! conserved magnetic moment
433 
434  ! check if the particle is in the internal ghost cells
435  int_factor =1.0d0
436 
438  ! if particle is not in the grid an euler timestep is taken instead of a RK4
439  ! timestep. Then based on that we do an interpolation and check how much further
440  ! the timestep for the RK4 has to be restricted.
441  ! factor to make integration more accurate for particles near the internal
442  ! ghost cells. This factor can be changed during integration after an
443  ! interpolation error. But one should be careful with timesteps for i/o
444 
445  ! flat interpolation:
446  {ic^d = int((y(^d)-rnode(rpxmin^d_,igrid_working))/rnode(rpdx^d_,igrid_working)) + 1 + nghostcells\}
447 
448  ! linear interpolation:
449  {
450  if (ps(igrid_working)%x({ic^dd},^d) .lt. y(^d)) then
451  ic1^d = ic^d
452  else
453  ic1^d = ic^d -1
454  end if
455  ic2^d = ic1^d + 1
456  \}
457 
458  int_factor =0.5d0
459 
460  {^d&
461  if (ic1^d .le. ixglo^d-2 .or. ic2^d .ge. ixghi^d+2) then
462  int_factor = 0.05d0
463  end if
464  \}
465 
466  {^d&
467  if (ic1^d .eq. ixglo^d-1 .or. ic2^d .eq. ixghi^d+1) then
468  int_factor = 0.1d0
469  end if
470  \}
471 
472  dt_p=int_factor*dt_p
473  end if
474 
475  ! replace the solution vector with the original as it was before the Euler timestep
476  y(1:ndir+2) = ytmp(1:ndir+2)
477 
478  particle(ipart)%self%x(1:ndir) = ytmp(1:ndir) ! position of guiding center
479  particle(ipart)%self%u(1) = ytmp(ndir+1) ! parallel momentum component (gamma v||)
480  particle(ipart)%self%u(2) = ytmp(ndir+2) ! conserved magnetic moment
481 
482  ! specify a minimum step hmin. If the timestep reaches this minimum, multiply by
483  ! a factor 100 to make sure the RK integration doesn't crash
484  h1 = dt_p/2.0d0; hmin=1.0d-9; h_old=dt_p/2.0d0
485 
486  if(h1 .lt. hmin)then
487  h1=hmin
488  dt_p=2.0d0*h1
489  endif
490 
491  if (any(y .ne. y)) then
492  call mpistop("NaNs DETECTED IN GCA_INTEGRATE BEFORE ODEINT CALL! ABORTING...")
493  end if
494 
495  ! RK4 integration with adaptive stepwidth
496  call odeint(y,nvar,tloc,tloc+dt_p,eps,h1,hmin,nok,nbad,derivs_gca_rk,rkqs,ierror)
497 
498  if (ierror /= 0) then
499  print *, "odeint returned error code", ierror
500  print *, "1 means hmin too small, 2 means MAXSTP exceeded"
501  print *, "Having a problem with particle", iipart
502  end if
503 
504  if (any(y .ne. y)) then
505  call mpistop("NaNs DETECTED IN GCA_INTEGRATE AFTER ODEINT CALL! ABORTING...")
506  end if
507 
508  ! original RK integration without interpolation in ghost cells
509 ! call odeint(y,nvar,tloc,tloc+dt_p,eps,h1,hmin,nok,nbad,derivs_gca,rkqs)
510 
511  ! final solution vector after rk integration
512  particle(ipart)%self%x(1:ndir) = y(1:ndir)
513  particle(ipart)%self%u(1) = y(ndir+1)
514  particle(ipart)%self%u(2) = y(ndir+2)
515  !particle(ipart)%self%u(3) = y(ndir+3)
516 
517  ! now calculate other quantities, mean Lorentz factor, drifts, perpendicular velocity:
518  call get_vec(bp, igrid_working,y(1:ndir),tloc+dt_p,b)
519  call get_vec(vp, igrid_working,y(1:ndir),tloc+dt_p,vfluid)
520  call get_vec(jp, igrid_working,y(1:ndir),tloc+dt_p,current)
521  e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) + particles_eta*current(1)
522  e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) + particles_eta*current(2)
523  e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) + particles_eta*current(3)
524 
525  absb = sqrt(sum(b(:)**2))
526  bhat(1:ndir) = b(1:ndir) / absb
527 
528  epar = sum(e(:)*bhat(:))
529 
530  call cross(e,bhat,ve)
531 
532  ve(1:ndir) = ve(1:ndir) / absb
533  veabs = sqrt(sum(ve(:)**2))
534  if (relativistic) then
535  kappa = 1.d0/sqrt(1.0d0 - sum(ve(:)**2)/c_norm**2)
536  else
537  kappa = 1.d0
538  end if
539  mr = y(ndir+2); upar = y(ndir+1); m=particle(ipart)%self%m; q=particle(ipart)%self%q
540  if (relativistic) then
541  gamma = sqrt(1.0d0+upar**2/c_norm**2+2.0d0*mr*absb/m/c_norm**2)*kappa
542  else
543  gamma = 1.d0
544  end if
545 
546  particle(ipart)%self%u(3) = gamma
547 
548  ! Time update
549  particle(ipart)%self%time = particle(ipart)%self%time + dt_p
550 
551  ! Update payload
552  call gca_update_payload(particle(ipart)%igrid,ps(particle(ipart)%igrid)%w,pso(particle(ipart)%igrid)%w,ps(particle(ipart)%igrid)%x, &
553  particle(ipart)%self%x,particle(ipart)%self%u,q,m,defpayload,ndefpayload,particle(ipart)%self%time)
554  particle(ipart)%payload(1:ndefpayload) = defpayload
555  if (associated(usr_update_payload)) then
556  call usr_update_payload(particle(ipart)%igrid,ps(particle(ipart)%igrid)%w,pso(particle(ipart)%igrid)%w,ps(particle(ipart)%igrid)%x,&
557  particle(ipart)%self%x,particle(ipart)%self%u,q,m,usrpayload,nusrpayload,particle(ipart)%self%time)
558  particle(ipart)%payload(ndefpayload+1:npayload) = usrpayload
559  end if
560 
561  end do
562 
563  end subroutine gca_integrate_particles
564 
565  subroutine derivs_gca_rk(t_s,y,dydt)
567 
568  double precision :: t_s, y(ndir+2)
569  double precision :: dydt(ndir+2)
570 
571  double precision,dimension(ndir):: vE, b, e, x, bhat, bdotgradb, vEdotgradb, gradkappaB, vfluid, current
572  double precision,dimension(ndir):: bdotgradvE, vEdotgradvE, u, utmp1, utmp2, utmp3
573  double precision :: upar, Mr, gamma, absb, q, m, epar, kappa
574  integer :: ic^D
575 
576  ! Here the terms in the guiding centre equations of motion are interpolated for
577  ! the RK integration. The interpolation is also done in the ghost cells such
578  ! that the RK integration does not give an error
579 
580  q = particle(ipart_working)%self%q
581  m = particle(ipart_working)%self%m
582 
583  x(1:ndir) = y(1:ndir)
584  upar = y(ndir+1) ! gamma v||
585  mr = y(ndir+2)
586  !gamma = y(ndir+3)
587 
588  if (any(x .ne. x)) then
589  write(*,*) "ERROR IN DERIVS_GCA_RK: NaNs IN X OR Y!"
590  write(*,*) "x",x
591  write(*,*) "y",y(ndir+1:ndir+2)
592  call mpistop("ABORTING...")
593  end if
594 
595  call get_vec(bp, igrid_working,x,t_s,b)
596  call get_vec(vp, igrid_working,x,t_s,vfluid)
597  call get_vec(jp, igrid_working,x,t_s,current)
598  e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) + particles_eta*current(1)
599  e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) + particles_eta*current(2)
600  e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) + particles_eta*current(3)
601  call get_vec(b_dot_grad_b, igrid_working,x,t_s,bdotgradb)
602  call get_vec(ve_dot_grad_b, igrid_working,x,t_s,vedotgradb)
603  call get_vec(grad_kappa_b, igrid_working,x,t_s,gradkappab)
604  call get_vec(b_dot_grad_ve, igrid_working,x,t_s,bdotgradve)
605  call get_vec(ve_dot_grad_ve, igrid_working,x,t_s,vedotgradve)
606 
607  if (any(b .ne. b) .or. any(e .ne. e) &
608  .or. any(bdotgradb .ne. bdotgradb) .or. any(vedotgradb .ne. vedotgradb) &
609  .or. any(gradkappab .ne. gradkappab) .or. any(bdotgradve .ne. bdotgradve) &
610  .or. any(vedotgradve .ne. vedotgradve)) then
611  write(*,*) "ERROR IN DERIVS_GCA_RK: NaNs IN FIELD QUANTITIES!"
612  write(*,*) "b",b
613  write(*,*) "e",e
614  write(*,*) "bdotgradb",bdotgradb
615  write(*,*) "vEdotgradb",vedotgradb
616  write(*,*) "gradkappaB",gradkappab
617  write(*,*) "bdotgradvE",bdotgradve
618  write(*,*) "vEdotgradvE",vedotgradve
619  call mpistop("ABORTING...")
620  end if
621 
622  absb = sqrt(sum(b(:)**2))
623  if (absb .gt. 0.d0) then
624  bhat(1:ndir) = b(1:ndir) / absb
625  else
626  bhat = 0.d0
627  end if
628  epar = sum(e(:)*bhat(:))
629 
630  call cross(e,bhat,ve)
631  if (absb .gt. 0.d0) ve(1:ndir) = ve(1:ndir) / absb
632 
633  if (relativistic) then
634  kappa = 1.d0/sqrt(1.0d0 - sum(ve(:)**2)/c_norm**2)
635  gamma = sqrt(1.0d0+upar**2/c_norm**2+2.0d0*mr*absb/m/c_norm**2)*kappa
636  else
637  kappa = 1.d0
638  gamma = 1.d0
639  end if
640 
641  if (absb .gt. 0.d0) then
642  utmp1(1:ndir) = bhat(1:ndir)/(absb/kappa**2)
643  else
644  utmp1 = 0.d0
645  end if
646  utmp2(1:ndir) = mr/(gamma*q)*gradkappab(1:ndir) &
647  + m/q* (upar**2/gamma*bdotgradb(1:ndir) + upar*vedotgradb(1:ndir) &
648  + upar*bdotgradve(1:ndir) + gamma*vedotgradve(1:ndir))
649  if (relativistic) then
650  utmp2(1:ndir) = utmp2(1:ndir) + upar*epar/(gamma)*ve(1:ndir)
651  end if
652 
653  call cross(utmp1,utmp2,utmp3)
654  u(1:ndir) = ve(1:ndir) + utmp3(1:ndir)
655 
656  ! done assembling the terms, now write rhs:
657  dydt(1:ndir) = ( u(1:ndir) + upar/gamma * bhat(1:ndir) )
658  dydt(ndir+1) = q/m*epar - mr/(m*gamma) * sum(bhat(:)*gradkappab(:)) &
659  + sum(ve(:)*(upar*bdotgradb(:)+gamma*vedotgradb(:)))
660  dydt(ndir+2) = 0.0d0 ! magnetic moment is conserved
661 
662  end subroutine derivs_gca_rk
663 
664  subroutine derivs_gca(t_s,y,dydt)
666 
667  double precision :: t_s, y(ndir+2)
668  double precision :: dydt(ndir+2)
669 
670  double precision,dimension(ndir):: vE, b, e, x, bhat, bdotgradb, vEdotgradb, gradkappaB, vfluid, current
671  double precision,dimension(ndir):: bdotgradvE, vEdotgradvE, u, utmp1, utmp2, utmp3
672  double precision :: upar, Mr, gamma, absb, q, m, epar, kappa
673 
674  ! Here the normal interpolation is done for the terms in the GCA equations of motion
675 
676  q = particle(ipart_working)%self%q
677  m = particle(ipart_working)%self%m
678 
679  x(1:ndir) = y(1:ndir)
680  upar = y(ndir+1) ! gamma v||
681  mr = y(ndir+2)
682  !gamma = y(ndir+3)
683 
684  if (any(x .ne. x)) then
685  call mpistop("ERROR IN DERIVS_GCA: NaNs IN X! ABORTING...")
686  end if
687 
688  call get_vec(bp, igrid_working,x,t_s,b)
689  call get_vec(vp, igrid_working,x,t_s,vfluid)
690  call get_vec(jp, igrid_working,x,t_s,current)
691  e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) + particles_eta*current(1)
692  e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) + particles_eta*current(2)
693  e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) + particles_eta*current(3)
694  call get_vec(b_dot_grad_b, igrid_working,x,t_s,bdotgradb)
695  call get_vec(ve_dot_grad_b, igrid_working,x,t_s,vedotgradb)
696  call get_vec(grad_kappa_b, igrid_working,x,t_s,gradkappab)
697  call get_vec(b_dot_grad_ve, igrid_working,x,t_s,bdotgradve)
698  call get_vec(ve_dot_grad_ve, igrid_working,x,t_s,vedotgradve)
699 
700  absb = sqrt(sum(b(:)**2))
701  if (absb .gt. 0.d0) then
702  bhat(1:ndir) = b(1:ndir) / absb
703  else
704  bhat = 0.d0
705  end if
706 
707  epar = sum(e(:)*bhat(:))
708  call cross(e,bhat,ve)
709  if (absb .gt. 0.d0) ve(1:ndir) = ve(1:ndir) / absb
710 
711  if (relativistic) then
712  kappa = sqrt(1.0d0 - sum(ve(:)**2)/c_norm**2)
713  gamma = sqrt(1.0d0+upar**2/c_norm**2+2.0d0*mr*absb/m/c_norm**2)*kappa
714  else
715  kappa = 1.d0
716  gamma = 1.d0
717  end if
718  if (absb .gt. 0.d0) then
719  utmp1(1:ndir) = bhat(1:ndir)/(absb/kappa**2)
720  else
721  utmp1 = 0.d0
722  end if
723  utmp2(1:ndir) = mr/(gamma*q)*gradkappab(1:ndir) &
724  + m/q* (upar**2/gamma*bdotgradb(1:ndir) + upar*vedotgradb(1:ndir) &
725  + upar*bdotgradve(1:ndir) + gamma*vedotgradve(1:ndir))
726  if (relativistic) then
727  utmp2(1:ndir) = utmp2(1:ndir) + upar*epar/(gamma)*ve(1:ndir)
728  end if
729 
730  call cross(utmp1,utmp2,utmp3)
731  u(1:ndir) = ve(1:ndir) + utmp3(1:ndir)
732 
733  ! done assembling the terms, now write rhs:
734  dydt(1:ndir) = ( u(1:ndir) + upar/gamma * bhat(1:ndir) )
735  dydt(ndir+1) = q/m*epar - mr/(m*gamma) * sum(bhat(:)*gradkappab(:)) &
736  + sum(ve(:)*(upar*bdotgradb(:)+gamma*vedotgradb(:)))
737  dydt(ndir+2) = 0.0d0 ! magnetic moment is conserved
738 
739  end subroutine derivs_gca
740 
741  !> Update payload subroutine
742  subroutine gca_update_payload(igrid,w,wold,xgrid,xpart,upart,qpart,mpart,mypayload,mynpayload,particle_time)
744  integer, intent(in) :: igrid,mynpayload
745  double precision, intent(in) :: w(ixG^T,1:nw),wold(ixG^T,1:nw)
746  double precision, intent(in) :: xgrid(ixG^T,1:ndim),xpart(1:ndir),upart(1:ndir),qpart,mpart,particle_time
747  double precision, intent(out) :: mypayload(mynpayload)
748  double precision, dimension(1:ndir) :: vE, e, b, bhat, vfluid, current
749  double precision, dimension(1:ndir) :: drift1, drift2
750  double precision, dimension(1:ndir) :: drift3, drift4, drift5, drift6, drift7
751  double precision, dimension(1:ndir) :: bdotgradb, vEdotgradb, gradkappaB
752  double precision, dimension(1:ndir) :: bdotgradvE, vEdotgradvE
753  double precision, dimension(1:ndir) :: gradBdrift, reldrift, bdotgradbdrift
754  double precision, dimension(1:ndir) :: vEdotgradbdrift, bdotgradvEdrift
755  double precision, dimension(1:ndir) :: vEdotgradvEdrift
756  double precision :: kappa, upar, absb, gamma, vpar, vEabs
757  double precision :: gradBdrift_abs, reldrift_abs, epar
758  double precision :: bdotgradbdrift_abs, vEdotgradbdrift_abs
759  double precision :: bdotgradvEdrift_abs, vEdotgradvEdrift_abs
760  double precision :: momentumpar1, momentumpar2, momentumpar3, momentumpar4
761 
762  call get_vec(bp, igrid,xpart(1:ndir),particle_time,b)
763  call get_vec(vp, igrid,xpart(1:ndir),particle_time,vfluid)
764  call get_vec(jp, igrid,xpart(1:ndir),particle_time,current)
765  e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) + particles_eta*current(1)
766  e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) + particles_eta*current(2)
767  e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) + particles_eta*current(3)
768 
769  absb = sqrt(sum(b(:)**2))
770  bhat(1:ndir) = b(1:ndir) / absb
771  epar = sum(e(:)*bhat(:))
772  call cross(e,bhat,ve)
773  ve(1:ndir) = ve(1:ndir) / absb
774  veabs = sqrt(sum(ve(:)**2))
775  if (relativistic) then
776  kappa = 1.d0/sqrt(1.0d0 - sum(ve(:)**2)/c_norm**2)
777  else
778  kappa = 1.d0
779  end if
780  vpar = upart(1)/upart(3)
781  upar = upart(1)
782 
783  call get_vec(b_dot_grad_b, igrid,xpart(1:ndir),particle_time,bdotgradb)
784  call get_vec(ve_dot_grad_b, igrid,xpart(1:ndir),particle_time,vedotgradb)
785  call get_vec(grad_kappa_b, igrid,xpart(1:ndir),particle_time,gradkappab)
786  call get_vec(b_dot_grad_ve, igrid,xpart(1:ndir),particle_time,bdotgradve)
787  call get_vec(ve_dot_grad_ve, igrid,xpart(1:ndir),particle_time,vedotgradve)
788 
789  drift1(1:ndir) = bhat(1:ndir)/(absb/kappa**2)
790  drift2(1:ndir) = upart(2)/(upart(3)*qpart)*gradkappab(1:ndir)
791 
792  call cross(drift1,drift2,gradbdrift)
793  gradbdrift_abs = sqrt(sum(gradbdrift(:)**2))
794 
795  drift3(1:ndir) = upar*epar/upart(3)*ve(1:ndir)
796  call cross(drift1,drift3,reldrift)
797  reldrift_abs = sqrt(sum(reldrift(:)**2))
798 
799  drift4(1:ndir) = mpart/qpart* ( upar**2/upart(3)*bdotgradb(1:ndir))
800  call cross(drift1,drift4,bdotgradbdrift)
801  bdotgradbdrift_abs = sqrt(sum(bdotgradbdrift(:)**2))
802 
803  drift5(1:ndir) = mpart/qpart* ( upar*vedotgradb(1:ndir))
804  call cross(drift1,drift5,vedotgradbdrift)
805  vedotgradbdrift_abs = sqrt(sum(vedotgradbdrift(:)**2))
806 
807  drift6(1:ndir) = mpart/qpart* ( upar*bdotgradve(1:ndir))
808  call cross(drift1,drift6,bdotgradvedrift)
809  bdotgradvedrift_abs = sqrt(sum(bdotgradvedrift(:)**2))
810 
811  drift7(1:ndir) = mpart/qpart* (upart(3)*vedotgradve(1:ndir))
812  call cross(drift1,drift7,vedotgradvedrift)
813  vedotgradvedrift_abs = sqrt(sum(vedotgradvedrift(:)**2))
814 
815  momentumpar1 = qpart/mpart*epar
816  momentumpar2 = -(upart(2)/mpart/upart(3))*sum(bhat(:)*gradkappab(:))
817  momentumpar3 = upar*sum(ve(:)*bdotgradb(:))
818  momentumpar4 = upart(3)*sum(ve(:)*vedotgradb(:))
819 
820  ! Payload update
821  if (mynpayload > 0) then
822  ! current gyroradius
823  mypayload(1) = sqrt(2.0d0*mpart*upart(2)*absb)/abs(qpart*absb)
824  end if
825  if (mynpayload > 1) then
826  ! pitch angle
827  mypayload(2) = atan2(sqrt((2.0d0*upart(2)*absb)/(mpart*upart(3)**2)),vpar)
828  end if
829  if (mynpayload > 2) then
830  ! particle v_perp
831  mypayload(3) = sqrt((2.0d0*upart(2)*absb)/(mpart*upart(3)**2))
832  end if
833  if (mynpayload > 3) then
834  ! particle parallel momentum term 1
835  mypayload(4) = momentumpar1
836  end if
837  if (mynpayload > 4) then
838  ! particle parallel momentum term 2
839  mypayload(5) = momentumpar2
840  end if
841  if (mynpayload > 5) then
842  ! particle parallel momentum term 3
843  mypayload(6) = momentumpar3
844  end if
845  if (mynpayload > 6) then
846  ! particle parallel momentum term 4
847  mypayload(7) = momentumpar4
848  end if
849  if (mynpayload > 7) then
850  ! particle ExB drift
851  mypayload(8) = veabs
852  end if
853  if (mynpayload > 8) then
854  ! relativistic drift
855  mypayload(9) = gradbdrift_abs
856  end if
857  if (mynpayload > 9) then
858  ! gradB drift
859  mypayload(10) = reldrift_abs
860  end if
861  if (mynpayload > 10) then
862  ! bdotgradb drift
863  mypayload(11) = bdotgradbdrift_abs
864  end if
865  if (mynpayload > 11) then
866  ! vEdotgradb drift
867  mypayload(12) = vedotgradbdrift_abs
868  end if
869  if (mynpayload > 12) then
870  ! bdotgradvE drift
871  mypayload(13) = bdotgradvedrift_abs
872  end if
873  if (mynpayload > 13) then
874  ! vEdotgradvE drift
875  mypayload(14) = vedotgradvedrift_abs
876  end if
877 
878  end subroutine gca_update_payload
879 
880  function gca_get_particle_dt(partp, end_time) result(dt_p)
881  use mod_odeint
883  type(particle_ptr), intent(in) :: partp
884  double precision, intent(in) :: end_time
885  double precision :: dt_p
886 
887  double precision :: tout, dt_particles_mype, dt_cfl0, dt_cfl1, dt_a
888  double precision :: dxmin, vp, a, gammap
889  double precision :: v(ndir), y(ndir+2),ytmp(ndir+2), dydt(ndir+2), v0(ndir), v1(ndir), dydt1(ndir+2)
890  double precision :: ap0, ap1, dt_cfl_ap0, dt_cfl_ap1, dt_cfl_ap
891  double precision :: dt_euler, dt_tmp
892  ! make these particle cfl conditions more restrictive if you are interpolating out of the grid
893  double precision :: cfl, uparcfl
894  double precision, parameter :: uparmin=1.0d-6*const_c
895  integer :: ipart, iipart, nout, ic^d, igrid_particle, ipe_particle, ipe
896  logical :: bc_applied
897 
898  if (const_dt_particles > 0) then
899  dt_p = const_dt_particles
900  return
901  end if
902 
903  cfl = particles_cfl
904  uparcfl = particles_cfl
905 
906  igrid_working = partp%igrid
907  ipart_working = partp%self%index
908  dt_tmp = (end_time - partp%self%time)
909  if(dt_tmp .le. 0.0d0) dt_tmp = smalldouble
910  ! make sure we step only one cell at a time, first check CFL at current location
911  ! then we make an Euler step to the new location and check the new CFL
912  ! we simply take the minimum of the two timesteps.
913  ! added safety factor cfl:
914  dxmin = min({rnode(rpdx^d_,partp%igrid)},bigdouble)*cfl
915  ! initial solution vector:
916  y(1:ndir) = partp%self%x(1:ndir) ! position of guiding center
917  y(ndir+1) = partp%self%u(1) ! parallel momentum component (gamma v||)
918  y(ndir+2) = partp%self%u(2) ! conserved magnetic moment
919  ytmp=y
920  !y(ndir+3) = partp%self%u(3) ! Lorentz factor of guiding centre
921 
922  call derivs_gca(partp%self%time,y,dydt)
923  v0(1:ndir) = dydt(1:ndir)
924  ap0 = dydt(ndir+1)
925 
926  ! guiding center velocity:
927  v(1:ndir) = abs(dydt(1:ndir))
928  vp = sqrt(sum(v(:)**2))
929 
930  dt_cfl0 = dxmin / max(vp, smalldouble)
931  dt_cfl_ap0 = uparcfl * abs(max(abs(y(ndir+1)),uparmin) / max(ap0, smalldouble))
932  !dt_cfl_ap0 = min(dt_cfl_ap0, uparcfl * sqrt(abs(unit_length*dxmin/(ap0+smalldouble))) )
933 
934  ! make an Euler step with the proposed timestep:
935  ! new solution vector:
936  dt_euler = min(dt_tmp,dt_cfl0,dt_cfl_ap0)
937  y(1:ndir+2) = y(1:ndir+2) + dt_euler * dydt(1:ndir+2)
938 
939  partp%self%x(1:ndir) = y(1:ndir) ! position of guiding center
940  partp%self%u(1) = y(ndir+1) ! parallel momentum component (gamma v||)
941  partp%self%u(2) = y(ndir+2) ! conserved magnetic moment
942 
943  ! first check if the particle is outside the physical domain or in the ghost cells
945  y(1:ndir+2) = ytmp(1:ndir+2)
946  end if
947 
948  call derivs_gca_rk(partp%self%time+dt_euler,y,dydt)
949  !call derivs_gca(partp%self%time+dt_euler,y,dydt)
950 
951  v1(1:ndir) = dydt(1:ndir)
952  ap1 = dydt(ndir+1)
953 
954  ! guiding center velocity:
955  v(1:ndir) = abs(dydt(1:ndir))
956  vp = sqrt(sum(v(:)**2))
957 
958  dt_cfl1 = dxmin / max(vp, smalldouble)
959  dt_cfl_ap1 = uparcfl * abs(max(abs(y(ndir+1)),uparmin) / max(ap1, smalldouble))
960  !dt_cfl_ap1 = min(dt_cfl_ap1, uparcfl * sqrt(abs(unit_length*dxmin/(ap1+smalldouble))) )
961 
962  dt_tmp = min(dt_euler, dt_cfl1, dt_cfl_ap1)
963 
964  partp%self%x(1:ndir) = ytmp(1:ndir) ! position of guiding center
965  partp%self%u(1) = ytmp(ndir+1) ! parallel momentum component (gamma v||)
966  partp%self%u(2) = ytmp(ndir+2) ! conserved magnetic moment
967  !dt_tmp = min(dt_cfl1, dt_cfl_ap1)
968 
969  ! time step due to parallel acceleration:
970  ! The standard thing, dt=sqrt(dx/a) where we compute a from d(gamma v||)/dt and d(gamma)/dt
971  ! dt_ap = sqrt(abs(dxmin*unit_length*y(ndir+3)/( dydt(ndir+1) - y(ndir+1)/y(ndir+3)*dydt(ndir+3) ) ) )
972  ! vp = sqrt(sum(v(1:ndir)**))
973  ! gammap = sqrt(1.0d0/(1.0d0-(vp/const_c)**2))
974  ! ap = const_c**2/vp*gammap**(-3)*dydt(ndir+3)
975  ! dt_ap = sqrt(dxmin*unit_length/ap)
976 
977  !dt_a = bigdouble
978  !if (dt_euler .gt. smalldouble) then
979  ! a = sqrt(sum((v1(1:ndir)-v0(1:ndir))**2))/dt_euler
980  ! dt_a = min(sqrt(dxmin/a),bigdouble)
981  !end if
982 
983  !dt_p = min(dt_tmp , dt_a)
984  dt_p = dt_tmp
985 
986  ! Make sure we don't advance beyond end_time
987  call limit_dt_endtime(end_time - partp%self%time, dt_p)
988 
989  end function gca_get_particle_dt
990 
991 end module mod_particle_gca
subroutine mpistop(message)
Exit MPI-AMRVAC with an error message.
Definition: comm_lib.t:194
Module with geometry-related routines (e.g., divergence, curl)
Definition: mod_geometry.t:2
subroutine gradient(q, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q within ixL in direction idir.
Definition: mod_geometry.t:320
This module contains definitions of global parameters and variables and some generic functions/subrou...
integer ixghi
Upper index of grid block arrays.
double precision global_time
The global simulation time.
integer, parameter ndim
Number of spatial dimensions for grid variables.
integer icomm
The MPI communicator.
integer mype
The rank of the current MPI task.
integer, dimension(:), allocatable, parameter d
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ierrmpi
A global MPI error return code.
double precision c_norm
Normalised speed of light.
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
integer nghostcells
Number of ghost cells surrounding a grid.
integer, parameter ixglo
Lower index of grid block arrays (always 1)
This module packages odeint from numerical recipes.
Definition: mod_odeint.t:2
subroutine odeint(ystart, nvar, x1, x2, eps, h1, hmin, nok, nbad, derivs, rkqs, ierror)
Definition: mod_odeint.t:12
subroutine rkqs(y, dydx, n, x, htry, eps, yscal, hdid, hnext, derivs)
Definition: mod_odeint.t:115
Module with shared functionality for all the particle movers.
pure subroutine limit_dt_endtime(t_left, dt_p)
integer num_particles
Number of particles.
double precision const_dt_particles
If positive, a constant time step for the particles.
logical function particle_in_igrid(ipart, igrid)
Quick check if particle is still in igrid.
integer ngridvars
Number of variables for grid field.
integer nusrpayload
Number of user-defined payload variables for a particle.
double precision particles_eta
Resistivity.
subroutine find_particle_ipe(x, igrid_particle, ipe_particle)
pure subroutine get_lfac_from_velocity(v, lfac)
Get Lorentz factor from velocity.
integer, dimension(:), allocatable ep
Variable index for electric field.
subroutine fill_gridvars_default
This routine fills the particle grid variables with the default for mhd, i.e. only E and B.
integer npayload
Number of total payload variables for a particle.
integer, dimension(:), allocatable particles_active_on_mype
Array of identity numbers of active particles in current processor.
logical relativistic
Use a relativistic particle mover?
subroutine get_vec(ix, igrid, x, tloc, vec)
subroutine push_particle_into_particles_on_mype(ipart)
integer nparticles_active_on_mype
Number of active particles in current processor.
procedure(sub_define_additional_gridvars), pointer particles_define_additional_gridvars
integer nparticles
Identity number and total number of particles.
integer, dimension(:), allocatable bp
Variable index for magnetic field.
type(particle_ptr), dimension(:), allocatable particle
integer, dimension(:), allocatable vp
Variable index for fluid velocity.
procedure(sub_integrate), pointer particles_integrate
subroutine cross(a, b, c)
procedure(sub_fill_gridvars), pointer particles_fill_gridvars
integer ndefpayload
Number of default payload variables for a particle.
integer igrid_working
set the current igrid for the particle integrator:
integer, dimension(:), allocatable jp
Variable index for current.
integer ipart_working
set the current ipart for the particle integrator:
double precision particles_cfl
Particle CFL safety factor.
Particle mover with Newtonian/relativistic Guiding Center Approximation (GCA) By Jannis Teunissen,...
integer, dimension(:), allocatable, public, protected b_dot_grad_b
Variable index for (B . grad)B (curvature B drift)
subroutine derivs_gca(t_s, y, dydt)
subroutine gca_update_payload(igrid, w, wold, xgrid, xpart, upart, qpart, mpart, mypayload, mynpayload, particle_time)
Update payload subroutine.
subroutine derivs_gca_rk(t_s, y, dydt)
subroutine, public gca_init()
double precision function gca_get_particle_dt(partp, end_time)
subroutine, public gca_create_particles()
subroutine gca_fill_gridvars
integer, dimension(:), allocatable, public, protected b_dot_grad_ve
Variable index for polarization drift.
integer, dimension(:), allocatable, public, protected ve_dot_grad_ve
Variable index for polarization drift.
subroutine gca_integrate_particles(end_time)
integer, dimension(:), allocatable, public, protected grad_kappa_b
Variable index for gradient B, with relativistic correction 1/kappa where kappa = 1/sqrt(1 - E_perp^2...
integer, dimension(:), allocatable, public, protected ve_dot_grad_b
Variable index for curvature drift.
Module with all the methods that users can customize in AMRVAC.
procedure(check_particle), pointer usr_check_particle
procedure(create_particles), pointer usr_create_particles
procedure(update_payload), pointer usr_update_payload
procedure(particle_fields), pointer usr_particle_fields