MPI-AMRVAC 3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_particle_lorentz.t
Go to the documentation of this file.
1!> Particle mover with Newtonian/relativistic Boris scheme for Lorentz dynamics
2!> By Jannis Teunissen, Bart Ripperda, Oliver Porth, and Fabio Bacchini (2016-2020)
5
6 private
7
8 public :: lorentz_init
10 integer, parameter :: Boris=1, vay=2, hc=3, lm=4
11
12 ! Variables
13 public :: bp, ep, vp, jp, rhop
14
15contains
16
17 subroutine lorentz_init()
19 integer :: idir, nwx
20
21 if(physics_type/='mhd') call mpistop("Lorentz particles need magnetic field!")
22 if(ndir/=3) call mpistop("Lorentz particles need ndir=3!")
23
24 ! The first 6 gridvars are always B and E
25 ngridvars = ndir*2
26 nwx=0
27 ! density
28 if(particles_etah>0) nwx = 1
29
30 allocate(bp(ndir))
31 do idir = 1, ndir
32 nwx = nwx + 1
33 bp(idir) = nwx
34 end do
35 allocate(ep(ndir)) ! electric field
36 do idir = 1, ndir
37 nwx = nwx + 1
38 ep(idir) = nwx
39 end do
40 allocate(vp(ndir)) ! fluid velocity
41 do idir = 1, ndir
42 nwx = nwx + 1
43 vp(idir) = nwx
44 end do
45 allocate(jp(ndir)) ! current
46 do idir = 1, ndir
47 nwx = nwx + 1
48 jp(idir) = nwx
49 end do
50 nwx = nwx + 1 ! density
51 rhop = nwx
52
53 ngridvars=nwx
54
55 particles_fill_gridvars => lorentz_fill_gridvars
56
57 if (associated(particles_define_additional_gridvars)) then
59 end if
60
61 select case(integrator_type_particles)
62 case('Boris','boris')
63 integrator = boris
64 case('Vay','vay')
65 integrator = vay
66 case('HC','hc','higueracary')
67 integrator = hc
68 case('LM','lm','lapentamarkidis')
69 integrator = lm
70 case default
71 integrator = boris
72 end select
73
74 particles_integrate => lorentz_integrate_particles
75
76 end subroutine lorentz_init
77
79
82
83 double precision :: lfac
84 double precision :: x(3, num_particles)
85 double precision :: v(3, num_particles)
86 double precision :: q(num_particles)
87 double precision :: m(num_particles)
88 double precision :: rrd(num_particles,ndir)
89 double precision :: defpayload(ndefpayload)
90 double precision :: usrpayload(nusrpayload)
91 integer :: n, idir, igrid, ipe_particle, nparticles_local
92 logical :: follow(num_particles), check
93
94 follow = .false.
95 x = 0.0d0
96
97 if (mype==0) then
98 if (.not. associated(usr_create_particles)) then
99 ! Randomly distributed
100 do idir=1,ndir
101 do n = 1, num_particles
102 rrd(n,idir) = rng%unif_01()
103 end do
104 end do
105 do n=1, num_particles
106 {^d&x(^d,n) = xprobmin^d + rrd(n+1,^d) * (xprobmax^d - xprobmin^d)\}
107 end do
108 else
109 call usr_create_particles(num_particles, x, v, q, m, follow)
110 end if
111 end if
112
113 call mpi_bcast(x,3*num_particles,mpi_double_precision,0,icomm,ierrmpi)
114 call mpi_bcast(v,3*num_particles,mpi_double_precision,0,icomm,ierrmpi)
115 call mpi_bcast(q,num_particles,mpi_double_precision,0,icomm,ierrmpi)
116 call mpi_bcast(m,num_particles,mpi_double_precision,0,icomm,ierrmpi)
117 call mpi_bcast(follow,num_particles,mpi_logical,0,icomm,ierrmpi)
118
119 nparticles_local = 0
120
121 ! Find ipe and igrid responsible for particle
122 do n = 1, num_particles
123 call find_particle_ipe(x(:, n),igrid,ipe_particle)
124
125 particle(n)%igrid = igrid
126 particle(n)%ipe = ipe_particle
127
128 if (ipe_particle == mype) then
129 check = .true.
130
131 ! Check for user-defined modifications or rejection conditions
132 if (associated(usr_check_particle)) call usr_check_particle(igrid, x(:,n), v(:,n), q(n), m(n), follow(n), check)
133 if (check) then
135 else
136 cycle
137 end if
138
139 nparticles_local = nparticles_local + 1
140
141 call get_lfac_from_velocity(v(:,n), lfac)
142
143 allocate(particle(n)%self)
144 particle(n)%self%x = x(:,n)
145 particle(n)%self%u = v(:,n) * lfac
146 particle(n)%self%q = q(n)
147 particle(n)%self%m = m(n)
148 particle(n)%self%follow = follow(n)
149 particle(n)%self%index = n
150 particle(n)%self%time = global_time
151 particle(n)%self%dt = 0.0d0
152
153 ! initialise payloads for Lorentz module
154 allocate(particle(n)%payload(npayload))
155 call lorentz_update_payload(igrid,x(:,n),v(:,n)*lfac,q(n),m(n),defpayload,ndefpayload,0.d0)
156 particle(n)%payload(1:ndefpayload) = defpayload
157 if (associated(usr_update_payload)) then
158 call usr_update_payload(igrid,x(:,n),v(:,n)*lfac,q(n),m(n),usrpayload,nusrpayload,0.d0)
159 particle(n)%payload(ndefpayload+1:npayload) = usrpayload
160 end if
161 end if
162 end do
163
164 call mpi_allreduce(nparticles_local,nparticles,1,mpi_integer,mpi_sum,icomm,ierrmpi)
165
166 ! write the first csv file of particles
170
171 end subroutine lorentz_create_particles
172
173 subroutine lorentz_fill_gridvars
176 use mod_geometry
177
178 double precision, dimension(ixG^T,1:ndir) :: beta
179 double precision, dimension(ixG^T,1:nw) :: w,wold
180 double precision :: current(ixg^t,7-2*ndir:3)
181 double precision, dimension(ixG^T,1:ndir) :: ve, bhat
182 double precision, dimension(ixG^T) :: kappa, kappa_b, absb, tmp
183 integer :: igrid, iigrid, idir, idim
184 integer :: idirmin
185
186 ! Fill electromagnetic quantities
188
189 end subroutine lorentz_fill_gridvars
190
191 !> Relativistic particle integrator
192 subroutine lorentz_integrate_particles(end_time)
194 use mod_geometry
196 double precision, intent(in) :: end_time
197 double precision :: defpayload(ndefpayload)
198 double precision :: usrpayload(nusrpayload)
199 double precision :: lfac, q, m, dt_p
200 double precision :: xp(ndir), xpm(ndir), xpc(ndir), xpcm(ndir)
201 double precision :: up(ndir), upc(ndir), tp
202 double precision, dimension(ndir) :: b, e, bc, ec, vfluid, current
203 double precision :: rho, rhoold, td
204 integer :: ipart, iipart, igrid
205
206 do iipart=1,nparticles_active_on_mype
207 ipart = particles_active_on_mype(iipart);
208 q = particle(ipart)%self%q
209 m = particle(ipart)%self%m
210 igrid = particle(ipart)%igrid
211 xp = particle(ipart)%self%x
212 up = particle(ipart)%self%u
213 tp = particle(ipart)%self%time
214
215 dt_p = lorentz_get_particle_dt(particle(ipart), end_time)
216 particle(ipart)%self%dt = dt_p
217
218 ! Push particle over first half time step
219 ! all pushes done in Cartesian coordinates
220 call partcoord_to_cartesian(xp,xpc)
221 call partvec_to_cartesian(xp,up,upc)
222 call get_lfac(upc,lfac)
223 xpcm = xpc + 0.5d0 * dt_p * upc/lfac
224 call partcoord_from_cartesian(xpm,xpcm)
225 ! Fix xp if the 0,2*pi boundary was crossed in cylindrical/spherical coords
226 call fix_phi_crossing(xpm,igrid)
227
228 ! Get E, B at n+1/2 position
229 call get_bfield(igrid, xpm, tp+dt_p/2.d0, b)
230 call get_efield(igrid, xpm, tp+dt_p/2.d0, e)
231
232! call get_vec(vp, igrid, xpm, tp+dt_p/2.d0, vfluid)
233! call get_vec(jp, igrid, xpm, tp+dt_p/2.d0, current)
234! select case (coordinate)
235! case (Cartesian,Cartesian_stretched,spherical)
236! e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) + particles_eta*current(1)
237! e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) + particles_eta*current(2)
238! e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) + particles_eta*current(3)
239! case (cylindrical)
240! e(r_) = -vfluid(phi_)*b(z_)+vfluid(z_)*b(phi_) + particles_eta*current(r_)
241! e(phi_) = vfluid(r_)*b(z_)-vfluid(z_)*b(r_) + particles_eta*current(phi_)
242! e(z_) = -vfluid(r_)*b(phi_)+vfluid(phi_)*b(r_) + particles_eta*current(z_)
243! end select
244! if (particles_etah > zero) then
245! call interpolate_var(igrid,ixG^LL,ixM^LL,ps(igrid)%w(ixG^T,1),ps(igrid)%x,xpm,rho)
246! if (time_advance) then
247! td = (tp+dt_p/2.d0 - global_time) / dt
248! call interpolate_var(igrid,ixG^LL,ixM^LL,pso(igrid)%w(ixG^T,1),ps(igrid)%x,xpm,rhoold)
249! rho = rhoold * (1.d0-td) + rho * td
250! end if
251! select case (coordinate)
252! case (Cartesian,Cartesian_stretched,spherical)
253! e(1) = e(1) + particles_etah/rho * (current(2)*b(3) - current(3)*b(2))
254! e(2) = e(2) + particles_etah/rho * (-current(1)*b(3) + current(3)*b(1))
255! e(3) = e(3) + particles_etah/rho * (current(1)*b(2) - current(2)*b(1))
256! case (cylindrical)
257! e(r_) = e(r_) + particles_etah/rho * (current(phi_)*b(z_) - current(z_)*b(phi_))
258! e(phi_) = e(phi_) + particles_etah/rho * (-current(r_)*b(z_) + current(z_)*b(r_))
259! e(z_) = e(z_) + particles_etah/rho * (current(r_)*b(phi_) - current(phi_)*b(r_))
260! end select
261! end if
262
263 ! Convert fields to Cartesian frame
264 call partvec_to_cartesian(xpm,b,bc)
265 call partvec_to_cartesian(xpm,e,ec)
266
267 ! 'Kick' particle (update velocity) based on the chosen integrator
268 call lorentz_kick(upc,ec,bc,q,m,dt_p)
269
270 ! Push particle over second half time step
271 ! all pushes done in Cartesian coordinates
272 call get_lfac(upc,lfac)
273 xpc = xpcm + 0.5d0 * dt_p * upc/lfac
274 call partcoord_from_cartesian(xp,xpc)
275 ! Fix xp if the 0,2*pi boundary was crossed in cylindrical/spherical coords
276 call fix_phi_crossing(xp,igrid)
277 call partvec_from_cartesian(xp,up,upc)
278
279 ! Store updated x,u
280 particle(ipart)%self%x = xp
281 particle(ipart)%self%u = up
282
283 ! Time update
284 tp = tp + dt_p
285 particle(ipart)%self%time = tp
286
287 ! Update payload
288 call lorentz_update_payload(igrid,xp,up,q,m,defpayload,ndefpayload,tp)
289 particle(ipart)%payload(1:ndefpayload) = defpayload
290 if (associated(usr_update_payload)) then
291 call usr_update_payload(igrid,xp,up,q,m,usrpayload,nusrpayload,tp)
292 particle(ipart)%payload(ndefpayload+1:npayload) = usrpayload
293 end if
294
295 end do ! ipart loop
296
297 end subroutine lorentz_integrate_particles
298
299 !> Momentum update subroutine for full Lorentz dynamics
300 subroutine lorentz_kick(upart,e,b,q,m,dtp)
302 use mod_geometry
303 double precision, intent(in) :: e(ndir), b(ndir), q, m, dtp
304 double precision, intent(inout) :: upart(ndir)
305 double precision :: lfac, cosphi, sinphi, phi1, phi2, r, re, sigma, td
306 double precision, dimension(ndir) :: emom, uprime, tau, s, tmp, uplus, xcart1, xcart2, ucart2, radmom
307 double precision, dimension(ndir) :: upartk, vbar, fk, c1, c2, dupartk
308 double precision :: abserr, tol, lfack, j11, j12, j13, j21, j22, j23, j31, j32, j33
309 double precision :: ij11, ij12, ij13, ij21, ij22, ij23, ij31, ij32, ij33, det
310 integer :: nk, nkmax
311
312 ! Perform momentum update based on the chosen integrator
313 select case(integrator)
314
315 ! Boris integrator (works in Cartesian and cylindrical)
316 case(boris)
317 ! Momentum update
318 emom = q * e * dtp /(2.0d0 * m)
319 uprime = upart + emom
320 !!!!!! TODO: Adjust and document losses
321! if (losses) then
322! call get_lfac(particle(ipart)%self%u,lfac)
323! re = abs(q)**2 / (m * const_c**2)
324! call cross(upart,b,tmp)
325! radmom = - third * re**2 * lfac &
326! * ( sum((e(:)+tmp(:)/lfac)**2) &
327! - (sum(e(:)*upart(:))/lfac)**2 ) &
328! * particle(ipart)%self%u / m / const_c * dt_p
329! uprime = uprime + radmom
330! end if
331
332 call get_lfac(uprime,lfac)
333 tau = q * b * dtp / (2.0d0 * lfac * m)
334 s = 2.0d0 * tau / (1.0d0+sum(tau(:)**2))
335
336 call cross(uprime,tau,tmp)
337 call cross(uprime+tmp,s,tmp)
338 uplus = uprime + tmp
339
340 upart = uplus + emom
341 !!!!!! TODO: Adjust and document losses
342! if(losses) then
343! call cross(uplus,b,tmp)
344! radmom = - third * re**2 * lfac &
345! * ( sum((e(:)+tmp(:)/lfac)**2) &
346! - (sum(e(:)*uplus(:))/lfac)**2 ) &
347! * uplus / m / const_c * dt_p
348! upart = upart + radmom
349! end if
350
351 ! Vay integrator
352 case(vay)
353 call get_lfac(upart,lfac)
354 emom = q * e * dtp /(2.0d0 * m)
355 tau = q * b * dtp / (2.0d0 * m)
356
357 call cross(upart,tau,tmp)
358 uprime = upart + 2.d0*emom + tmp/lfac
359
360 call get_lfac(uprime,lfac)
361 sigma = lfac**2 - sum(tau(:)*tau(:))
362 lfac = sqrt((sigma + sqrt(sigma**2 &
363 + 4.d0 * (sum(tau(:)*tau(:)) + sum(uprime(:)*tau(:)/c_norm)**2))) / 2.d0)
364
365 call cross(uprime,tau,tmp)
366 upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / (1.d0+sum(tau(:)*tau(:))/lfac**2)
367
368 ! Higuera-Cary integrator
369 case(hc)
370 call get_lfac(upart,lfac)
371 emom = q * e * dtp /(2.0d0 * m)
372 tau = q * b * dtp / (2.0d0 * m)
373 uprime = upart + emom
374
375 call get_lfac(uprime,lfac)
376 sigma = lfac**2 - sum(tau(:)*tau(:))
377 lfac = sqrt((sigma + sqrt(sigma**2 &
378 + 4.d0 * (sum(tau(:)*tau(:)) + sum(uprime(:)*tau(:)/c_norm)**2))) / 2.d0)
379
380 call cross(uprime,tau,tmp)
381 upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / (1.d0+sum(tau(:)*tau(:))/lfac**2) &
382 + emom + tmp/lfac
383
384 ! Lapenta-Markidis integrator
385 case(lm)
386 ! Initialise iteration quantities
387 call get_lfac(upart,lfac)
388 upartk = upart
389 tau(:) = b(:)
390
391 ! START OF THE NONLINEAR CYCLE
392 abserr = 1.d0
393 tol=1.d-14
394 nkmax=10
395 nk=0
396 do while(abserr > tol .and. nk < nkmax)
397
398 nk=nk+1
399
400 call get_lfac(upartk,lfack)
401 vbar = (upart + upartk) / (lfac + lfack)
402 call cross(vbar,tau,tmp)
403
404 ! Compute residual vector
405 fk = upartk - upart - q*dtp/m * (e + tmp)
406
407 ! Compute auxiliary coefficients
408 c1 = (lfack + lfac - upartk(1:ndim) / lfack / c_norm**2 * (upartk + upart)) / (lfack + lfac)**2
409 c2 = - upartk / lfack / c_norm**2 / (lfack + lfac)**2
410
411 ! Compute Jacobian
412 j11 = 1. - q*dtp/m * (c2(1) * (upartk(2) + upart(2)) * tau(3) - c2(1) * (upartk(3) + upart(3)) * tau(2))
413 j12 = - q*dtp/m * (c1(2) * tau(3) - c2(2) * (upartk(3) + upart(3)) * tau(2))
414 j13 = - q*dtp/m * (c2(3) * (upartk(2) + upart(2)) * tau(3) - c1(3) * tau(2))
415 j21 = - q*dtp/m * (- c1(1) * tau(3) + c2(1) * (upartk(3) + upart(3)) * tau(1))
416 j22 = 1. - q*dtp/m * (- c2(2) * (upartk(1) + upart(1)) * tau(3) + c2(2) * (upartk(3) + upart(3)) * tau(1))
417 j23 = - q*dtp/m * (- c2(3) * (upartk(1) + upart(1)) * tau(3) + c1(3) * tau(1))
418 j31 = - q*dtp/m * (c1(1) * tau(2) - c2(1) * (upartk(2) + upart(2)) * tau(1))
419 j32 = - q*dtp/m * (c2(2) * (upartk(1) + upart(1)) * tau(2) - c1(2) * tau(1))
420 j33 = 1. - q*dtp/m * (c2(3) * (upartk(1) + upart(1)) * tau(2) - c2(3) * (upartk(2) + upart(2)) * tau(1))
421
422 ! Compute inverse Jacobian
423 det = j11*j22*j33 + j21*j32*j13 + j31*j12*j23 - j11*j32*j23 - j31*j22*j13 - j21*j12*j33
424 ij11 = (j22*j33 - j23*j32) / det
425 ij12 = (j13*j32 - j12*j33) / det
426 ij13 = (j12*j23 - j13*j22) / det
427 ij21 = (j23*j31 - j21*j33) / det
428 ij22 = (j11*j33 - j13*j31) / det
429 ij23 = (j13*j21 - j11*j23) / det
430 ij31 = (j21*j32 - j22*j31) / det
431 ij32 = (j12*j31 - j11*j32) / det
432 ij33 = (j11*j22 - j12*j21) / det
433
434 ! Compute new upartk = upartk - J^(-1) * F(upartk)
435 dupartk(1) = - (ij11 * fk(1) + ij12 * fk(2) + ij13 * fk(3))
436 dupartk(2) = - (ij21 * fk(1) + ij22 * fk(2) + ij23 * fk(3))
437 dupartk(3) = - (ij31 * fk(1) + ij32 * fk(2) + ij33 * fk(3))
438
439 ! Check convergence
440 upartk=upartk+dupartk
441 abserr=sqrt(sum(dupartk(:)*dupartk(:)))
442
443 end do
444 ! END OF THE NONLINEAR CYCLE
445
446 ! Update velocity
447 upart = upartk
448
449 end select
450
451 end subroutine lorentz_kick
452
453 !> Update payload subroutine
454 subroutine lorentz_update_payload(igrid,xpart,upart,qpart,mpart,mypayload,mynpayload,particle_time)
456 use mod_geometry
457 integer, intent(in) :: igrid,mynpayload
458 double precision, intent(in) :: xpart(1:ndir),upart(1:ndir),qpart,mpart,particle_time
459 double precision, intent(out) :: mypayload(mynpayload)
460 double precision :: b(3), e(3), tmp(3), lfac, vfluid(3), current(3), rho, rhoold, td
461
462 call get_bfield(igrid, xpart, particle_time, b)
463 call get_efield(igrid, xpart, particle_time, e)
464
465! call get_vec(bp, igrid, xpart,particle_time,b)
466! call get_vec(vp, igrid, xpart,particle_time,vfluid)
467! call get_vec(jp, igrid, xpart,particle_time,current)
468! select case (coordinate)
469! case (Cartesian,Cartesian_stretched,spherical)
470! e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) + particles_eta*current(1)
471! e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) + particles_eta*current(2)
472! e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) + particles_eta*current(3)
473! case (cylindrical)
474! e(r_) = -vfluid(phi_)*b(z_)+vfluid(z_)*b(phi_) + particles_eta*current(r_)
475! e(phi_) = vfluid(r_)*b(z_)-vfluid(z_)*b(r_) + particles_eta*current(phi_)
476! e(z_) = -vfluid(r_)*b(phi_)+vfluid(phi_)*b(r_) + particles_eta*current(z_)
477! end select
478! if (particles_etah > zero) then
479! call interpolate_var(igrid,ixG^LL,ixM^LL,ps(igrid)%w(ixG^T,1),ps(igrid)%x,xpart,rho)
480! if (time_advance) then
481! td = (particle_time - global_time) / dt
482! call interpolate_var(igrid,ixG^LL,ixM^LL,pso(igrid)%w(ixG^T,1),ps(igrid)%x,xpart,rhoold)
483! rho = rhoold * (1.d0-td) + rho * td
484! end if
485! select case (coordinate)
486! case (Cartesian,Cartesian_stretched,spherical)
487! e(1) = e(1) + particles_etah/rho * (current(2)*b(3) - current(3)*b(2))
488! e(2) = e(2) + particles_etah/rho * (-current(1)*b(3) + current(3)*b(1))
489! e(3) = e(3) + particles_etah/rho * (current(1)*b(2) - current(2)*b(1))
490! case (cylindrical)
491! e(r_) = e(r_) + particles_etah/rho * (current(phi_)*b(z_) - current(z_)*b(phi_))
492! e(phi_) = e(phi_) + particles_etah/rho * (-current(r_)*b(z_) + current(z_)*b(r_))
493! e(z_) = e(z_) + particles_etah/rho * (current(r_)*b(phi_) - current(phi_)*b(r_))
494! end select
495! end if
496
497 ! Payload update
498 ! Lorentz factor
499 if (mynpayload > 0) then
500 call get_lfac(upart,lfac)
501 mypayload(1) = lfac
502 end if
503
504 ! current gyroradius
505 if (mynpayload > 1) then
506 call cross(upart,b,tmp)
507 tmp = tmp / sqrt(sum(b(:)**2))
508 mypayload(2) = mpart/abs(qpart)*sqrt(sum(tmp(:)**2)) / sqrt(sum(b(:)**2))
509 end if
510
511 ! magnetic moment
512 if (mynpayload > 2) then
513 mypayload(3) = mpart*sum(tmp(:)**2)/(2.0d0*sqrt(sum(b(:)**2)))
514 end if
515
516 ! e.b
517 if (mynpayload > 3) then
518 mypayload(4) = sum(e(:)*b(:))
519 end if
520
521 end subroutine lorentz_update_payload
522
523 function lorentz_get_particle_dt(partp, end_time) result(dt_p)
525 use mod_geometry
526 type(particle_ptr), intent(in) :: partp
527 double precision, intent(in) :: end_time
528 double precision :: dt_p
529 double precision,dimension(ndir) :: b,v
530 double precision :: lfac,absb,dt_cfl
531 double precision :: tout
532 double precision, parameter :: cfl = 0.5d0
533 integer :: ipart, iipart, nout
534
535 if (const_dt_particles > 0) then
536 dt_p = const_dt_particles
537 return
538 end if
539
540 call get_vec(bp, partp%igrid,partp%self%x,partp%self%time,b)
541 absb = sqrt(sum(b(:)**2))
542 call get_lfac(partp%self%u,lfac)
543
544 ! CFL timestep
545 ! make sure we step only one cell at a time:
546 v(:) = abs(partp%self%u(:) / lfac)
547
548! ! convert to angular velocity:
549! if(coordinate ==cylindrical.and.phi_>0) then
550! v(phi_) = abs(v(phi_)/partp%self%x(r_))
551! end if
552
553 dt_cfl = min(bigdouble, &
554 {rnode(rpdx^d_,partp%igrid)/max(v(^d), smalldouble)})
555
556 if(coordinate ==cylindrical.and.phi_>0) then
557 ! phi-momentum leads to radial velocity:
558 if(phi_ .gt. ndim) dt_cfl = min(dt_cfl, &
559 sqrt(rnode(rpdx1_,partp%igrid)/partp%self%x(r_)) &
560 / v(phi_))
561 ! limit the delta phi of the orbit (just for aesthetic reasons):
562 dt_cfl = min(dt_cfl,0.1d0/max(v(phi_), smalldouble))
563 ! take some care at the axis:
564 dt_cfl = min(dt_cfl,(partp%self%x(r_)+smalldouble)/max(v(r_), smalldouble))
565 end if
566
567 dt_cfl = dt_cfl * cfl
568
569 ! bound by gyro-rotation:
570 dt_p = abs( dtheta * partp%self%m * lfac &
571 / (partp%self%q * absb) )
572
573 dt_p = min(dt_p, dt_cfl)
574
575 ! Make sure we don't advance beyond end_time
576 call limit_dt_endtime(end_time - partp%self%time, dt_p)
577
578 end function lorentz_get_particle_dt
579
580end module mod_particle_lorentz
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
integer coordinate
Definition mod_geometry.t:7
integer, parameter cylindrical
This module contains definitions of global parameters and variables and some generic functions/subrou...
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.
double precision, 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 r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
Module with shared functionality for all the particle movers.
subroutine partcoord_from_cartesian(xp, xpcart)
Convert to noncartesian coordinates.
pure subroutine limit_dt_endtime(t_left, dt_p)
integer num_particles
Number of particles.
subroutine fix_phi_crossing(xp, igrid)
Fix particle position when crossing the 0,2pi boundary in noncartesian coordinates.
double precision const_dt_particles
If positive, a constant time step for the particles.
subroutine write_particle_output()
double precision dtsave_particles
Time interval to save particles.
integer ngridvars
Number of variables for grid field.
subroutine get_efield(igrid, x, tloc, e)
double precision particles_etah
integer nusrpayload
Number of user-defined payload variables for a particle.
pure subroutine get_lfac(u, lfac)
Get Lorentz factor from relativistic momentum.
subroutine find_particle_ipe(x, igrid_particle, ipe_particle)
double precision dtheta
pure subroutine get_lfac_from_velocity(v, lfac)
Get Lorentz factor from velocity.
integer integrator
Integrator to be used for particles.
integer, dimension(:), allocatable ep
Variable index for electric field.
subroutine partvec_from_cartesian(xp, up, upcart)
Convert vector from Cartesian coordinates.
subroutine fill_gridvars_default
This routine fills the particle grid variables with the default for mhd, i.e. only E and B.
subroutine get_bfield(igrid, x, tloc, 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.
character(len=name_len) integrator_type_particles
String describing the particle integrator type.
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
subroutine partcoord_to_cartesian(xp, xpcart)
Convert position to Cartesian coordinates.
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
double precision t_next_output
Time to write next particle output.
subroutine partvec_to_cartesian(xp, up, upcart)
Convert vector to Cartesian coordinates.
integer ndefpayload
Number of default payload variables for a particle.
integer, dimension(:), allocatable jp
Variable index for current.
integer rhop
Variable index for density.
Particle mover with Newtonian/relativistic Boris scheme for Lorentz dynamics By Jannis Teunissen,...
subroutine, public lorentz_init()
subroutine, public lorentz_create_particles()
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