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 end subroutine lorentz_create_particles
167
168 subroutine lorentz_fill_gridvars
171 use mod_geometry
172
173 double precision, dimension(ixG^T,1:ndir) :: beta
174 double precision, dimension(ixG^T,1:nw) :: w,wold
175 double precision :: current(ixg^t,7-2*ndir:3)
176 double precision, dimension(ixG^T,1:ndir) :: ve, bhat
177 double precision, dimension(ixG^T) :: kappa, kappa_b, absb, tmp
178 integer :: igrid, iigrid, idir, idim
179 integer :: idirmin
180
181 ! Fill electromagnetic quantities
183
184 end subroutine lorentz_fill_gridvars
185
186 !> Relativistic particle integrator
187 subroutine lorentz_integrate_particles(end_time)
189 use mod_geometry
191 double precision, intent(in) :: end_time
192 double precision :: defpayload(ndefpayload)
193 double precision :: usrpayload(nusrpayload)
194 double precision :: lfac, q, m, dt_p
195 double precision :: xp(ndir), xpm(ndir), xpc(ndir), xpcm(ndir)
196 double precision :: up(ndir), upc(ndir), tp
197 double precision, dimension(ndir) :: b, e, bc, ec, vfluid, current
198 double precision :: rho, rhoold, td
199 integer :: ipart, iipart, igrid
200
201 do iipart=1,nparticles_active_on_mype
202 ipart = particles_active_on_mype(iipart);
203 q = particle(ipart)%self%q
204 m = particle(ipart)%self%m
205 igrid = particle(ipart)%igrid
206 xp = particle(ipart)%self%x
207 up = particle(ipart)%self%u
208 tp = particle(ipart)%self%time
209
210 dt_p = lorentz_get_particle_dt(particle(ipart), end_time)
211 particle(ipart)%self%dt = dt_p
212
213 ! Push particle over first half time step
214 ! all pushes done in Cartesian coordinates
215 call partcoord_to_cartesian(xp,xpc)
216 call partvec_to_cartesian(xp,up,upc)
217 call get_lfac(upc,lfac)
218 xpcm = xpc + 0.5d0 * dt_p * upc/lfac
219 call partcoord_from_cartesian(xpm,xpcm)
220 ! Fix xp if the 0,2*pi boundary was crossed in cylindrical/spherical coords
221 call fix_phi_crossing(xpm,igrid)
222
223 ! Get E, B at n+1/2 position
224 call get_bfield(igrid, xpm, tp+dt_p/2.d0, b)
225 call get_efield(igrid, xpm, tp+dt_p/2.d0, e)
226
227! call get_vec(vp, igrid, xpm, tp+dt_p/2.d0, vfluid)
228! call get_vec(jp, igrid, xpm, tp+dt_p/2.d0, current)
229! select case (coordinate)
230! case (Cartesian,Cartesian_stretched,spherical)
231! e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) + particles_eta*current(1)
232! e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) + particles_eta*current(2)
233! e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) + particles_eta*current(3)
234! case (cylindrical)
235! e(r_) = -vfluid(phi_)*b(z_)+vfluid(z_)*b(phi_) + particles_eta*current(r_)
236! e(phi_) = vfluid(r_)*b(z_)-vfluid(z_)*b(r_) + particles_eta*current(phi_)
237! e(z_) = -vfluid(r_)*b(phi_)+vfluid(phi_)*b(r_) + particles_eta*current(z_)
238! end select
239! if (particles_etah > zero) then
240! call interpolate_var(igrid,ixG^LL,ixM^LL,ps(igrid)%w(ixG^T,1),ps(igrid)%x,xpm,rho)
241! if (time_advance) then
242! td = (tp+dt_p/2.d0 - global_time) / dt
243! call interpolate_var(igrid,ixG^LL,ixM^LL,pso(igrid)%w(ixG^T,1),ps(igrid)%x,xpm,rhoold)
244! rho = rhoold * (1.d0-td) + rho * td
245! end if
246! select case (coordinate)
247! case (Cartesian,Cartesian_stretched,spherical)
248! e(1) = e(1) + particles_etah/rho * (current(2)*b(3) - current(3)*b(2))
249! e(2) = e(2) + particles_etah/rho * (-current(1)*b(3) + current(3)*b(1))
250! e(3) = e(3) + particles_etah/rho * (current(1)*b(2) - current(2)*b(1))
251! case (cylindrical)
252! e(r_) = e(r_) + particles_etah/rho * (current(phi_)*b(z_) - current(z_)*b(phi_))
253! e(phi_) = e(phi_) + particles_etah/rho * (-current(r_)*b(z_) + current(z_)*b(r_))
254! e(z_) = e(z_) + particles_etah/rho * (current(r_)*b(phi_) - current(phi_)*b(r_))
255! end select
256! end if
257
258 ! Convert fields to Cartesian frame
259 call partvec_to_cartesian(xpm,b,bc)
260 call partvec_to_cartesian(xpm,e,ec)
261
262 ! 'Kick' particle (update velocity) based on the chosen integrator
263 call lorentz_kick(upc,ec,bc,q,m,dt_p)
264
265 ! Push particle over second half time step
266 ! all pushes done in Cartesian coordinates
267 call get_lfac(upc,lfac)
268 xpc = xpcm + 0.5d0 * dt_p * upc/lfac
269 call partcoord_from_cartesian(xp,xpc)
270 ! Fix xp if the 0,2*pi boundary was crossed in cylindrical/spherical coords
271 call fix_phi_crossing(xp,igrid)
272 call partvec_from_cartesian(xp,up,upc)
273
274 ! Store updated x,u
275 particle(ipart)%self%x = xp
276 particle(ipart)%self%u = up
277
278 ! Time update
279 tp = tp + dt_p
280 particle(ipart)%self%time = tp
281
282 ! Update payload
283 call lorentz_update_payload(igrid,xp,up,q,m,defpayload,ndefpayload,tp)
284 particle(ipart)%payload(1:ndefpayload) = defpayload
285 if (associated(usr_update_payload)) then
286 call usr_update_payload(igrid,xp,up,q,m,usrpayload,nusrpayload,tp)
287 particle(ipart)%payload(ndefpayload+1:npayload) = usrpayload
288 end if
289
290 end do ! ipart loop
291
292 end subroutine lorentz_integrate_particles
293
294 !> Momentum update subroutine for full Lorentz dynamics
295 subroutine lorentz_kick(upart,e,b,q,m,dtp)
297 use mod_geometry
298 double precision, intent(in) :: e(ndir), b(ndir), q, m, dtp
299 double precision, intent(inout) :: upart(ndir)
300 double precision :: lfac, cosphi, sinphi, phi1, phi2, r, re, sigma, td
301 double precision, dimension(ndir) :: emom, uprime, tau, s, tmp, uplus, xcart1, xcart2, ucart2, radmom
302 double precision, dimension(ndir) :: upartk, vbar, fk, c1, c2, dupartk
303 double precision :: abserr, tol, lfack, j11, j12, j13, j21, j22, j23, j31, j32, j33
304 double precision :: ij11, ij12, ij13, ij21, ij22, ij23, ij31, ij32, ij33, det
305 integer :: nk, nkmax
306
307 ! Perform momentum update based on the chosen integrator
308 select case(integrator)
309
310 ! Boris integrator (works in Cartesian and cylindrical)
311 case(boris)
312 ! Momentum update
313 emom = q * e * dtp /(2.0d0 * m)
314 uprime = upart + emom
315 !!!!!! TODO: Adjust and document losses
316! if (losses) then
317! call get_lfac(particle(ipart)%self%u,lfac)
318! re = abs(q)**2 / (m * const_c**2)
319! call cross(upart,b,tmp)
320! radmom = - third * re**2 * lfac &
321! * ( sum((e(:)+tmp(:)/lfac)**2) &
322! - (sum(e(:)*upart(:))/lfac)**2 ) &
323! * particle(ipart)%self%u / m / const_c * dt_p
324! uprime = uprime + radmom
325! end if
326
327 call get_lfac(uprime,lfac)
328 tau = q * b * dtp / (2.0d0 * lfac * m)
329 s = 2.0d0 * tau / (1.0d0+sum(tau(:)**2))
330
331 call cross(uprime,tau,tmp)
332 call cross(uprime+tmp,s,tmp)
333 uplus = uprime + tmp
334
335 upart = uplus + emom
336 !!!!!! TODO: Adjust and document losses
337! if(losses) then
338! call cross(uplus,b,tmp)
339! radmom = - third * re**2 * lfac &
340! * ( sum((e(:)+tmp(:)/lfac)**2) &
341! - (sum(e(:)*uplus(:))/lfac)**2 ) &
342! * uplus / m / const_c * dt_p
343! upart = upart + radmom
344! end if
345
346 ! Vay integrator
347 case(vay)
348 call get_lfac(upart,lfac)
349 emom = q * e * dtp /(2.0d0 * m)
350 tau = q * b * dtp / (2.0d0 * m)
351
352 call cross(upart,tau,tmp)
353 uprime = upart + 2.d0*emom + tmp/lfac
354
355 call get_lfac(uprime,lfac)
356 sigma = lfac**2 - sum(tau(:)*tau(:))
357 lfac = sqrt((sigma + sqrt(sigma**2 &
358 + 4.d0 * (sum(tau(:)*tau(:)) + sum(uprime(:)*tau(:)/c_norm)**2))) / 2.d0)
359
360 call cross(uprime,tau,tmp)
361 upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / (1.d0+sum(tau(:)*tau(:))/lfac**2)
362
363 ! Higuera-Cary integrator
364 case(hc)
365 call get_lfac(upart,lfac)
366 emom = q * e * dtp /(2.0d0 * m)
367 tau = q * b * dtp / (2.0d0 * m)
368 uprime = upart + emom
369
370 call get_lfac(uprime,lfac)
371 sigma = lfac**2 - sum(tau(:)*tau(:))
372 lfac = sqrt((sigma + sqrt(sigma**2 &
373 + 4.d0 * (sum(tau(:)*tau(:)) + sum(uprime(:)*tau(:)/c_norm)**2))) / 2.d0)
374
375 call cross(uprime,tau,tmp)
376 upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / (1.d0+sum(tau(:)*tau(:))/lfac**2) &
377 + emom + tmp/lfac
378
379 ! Lapenta-Markidis integrator
380 case(lm)
381 ! Initialise iteration quantities
382 call get_lfac(upart,lfac)
383 upartk = upart
384 tau(:) = b(:)
385
386 ! START OF THE NONLINEAR CYCLE
387 abserr = 1.d0
388 tol=1.d-14
389 nkmax=10
390 nk=0
391 do while(abserr > tol .and. nk < nkmax)
392
393 nk=nk+1
394
395 call get_lfac(upartk,lfack)
396 vbar = (upart + upartk) / (lfac + lfack)
397 call cross(vbar,tau,tmp)
398
399 ! Compute residual vector
400 fk = upartk - upart - q*dtp/m * (e + tmp)
401
402 ! Compute auxiliary coefficients
403 c1 = (lfack + lfac - upartk(1:ndim) / lfack / c_norm**2 * (upartk + upart)) / (lfack + lfac)**2
404 c2 = - upartk / lfack / c_norm**2 / (lfack + lfac)**2
405
406 ! Compute Jacobian
407 j11 = 1. - q*dtp/m * (c2(1) * (upartk(2) + upart(2)) * tau(3) - c2(1) * (upartk(3) + upart(3)) * tau(2))
408 j12 = - q*dtp/m * (c1(2) * tau(3) - c2(2) * (upartk(3) + upart(3)) * tau(2))
409 j13 = - q*dtp/m * (c2(3) * (upartk(2) + upart(2)) * tau(3) - c1(3) * tau(2))
410 j21 = - q*dtp/m * (- c1(1) * tau(3) + c2(1) * (upartk(3) + upart(3)) * tau(1))
411 j22 = 1. - q*dtp/m * (- c2(2) * (upartk(1) + upart(1)) * tau(3) + c2(2) * (upartk(3) + upart(3)) * tau(1))
412 j23 = - q*dtp/m * (- c2(3) * (upartk(1) + upart(1)) * tau(3) + c1(3) * tau(1))
413 j31 = - q*dtp/m * (c1(1) * tau(2) - c2(1) * (upartk(2) + upart(2)) * tau(1))
414 j32 = - q*dtp/m * (c2(2) * (upartk(1) + upart(1)) * tau(2) - c1(2) * tau(1))
415 j33 = 1. - q*dtp/m * (c2(3) * (upartk(1) + upart(1)) * tau(2) - c2(3) * (upartk(2) + upart(2)) * tau(1))
416
417 ! Compute inverse Jacobian
418 det = j11*j22*j33 + j21*j32*j13 + j31*j12*j23 - j11*j32*j23 - j31*j22*j13 - j21*j12*j33
419 ij11 = (j22*j33 - j23*j32) / det
420 ij12 = (j13*j32 - j12*j33) / det
421 ij13 = (j12*j23 - j13*j22) / det
422 ij21 = (j23*j31 - j21*j33) / det
423 ij22 = (j11*j33 - j13*j31) / det
424 ij23 = (j13*j21 - j11*j23) / det
425 ij31 = (j21*j32 - j22*j31) / det
426 ij32 = (j12*j31 - j11*j32) / det
427 ij33 = (j11*j22 - j12*j21) / det
428
429 ! Compute new upartk = upartk - J^(-1) * F(upartk)
430 dupartk(1) = - (ij11 * fk(1) + ij12 * fk(2) + ij13 * fk(3))
431 dupartk(2) = - (ij21 * fk(1) + ij22 * fk(2) + ij23 * fk(3))
432 dupartk(3) = - (ij31 * fk(1) + ij32 * fk(2) + ij33 * fk(3))
433
434 ! Check convergence
435 upartk=upartk+dupartk
436 abserr=sqrt(sum(dupartk(:)*dupartk(:)))
437
438 end do
439 ! END OF THE NONLINEAR CYCLE
440
441 ! Update velocity
442 upart = upartk
443
444 end select
445
446 end subroutine lorentz_kick
447
448 !> Update payload subroutine
449 subroutine lorentz_update_payload(igrid,xpart,upart,qpart,mpart,mypayload,mynpayload,particle_time)
451 use mod_geometry
452 integer, intent(in) :: igrid,mynpayload
453 double precision, intent(in) :: xpart(1:ndir),upart(1:ndir),qpart,mpart,particle_time
454 double precision, intent(out) :: mypayload(mynpayload)
455 double precision :: b(3), e(3), tmp(3), lfac, vfluid(3), current(3), rho, rhoold, td
456
457 call get_bfield(igrid, xpart, particle_time, b)
458 call get_efield(igrid, xpart, particle_time, e)
459
460! call get_vec(bp, igrid, xpart,particle_time,b)
461! call get_vec(vp, igrid, xpart,particle_time,vfluid)
462! call get_vec(jp, igrid, xpart,particle_time,current)
463! select case (coordinate)
464! case (Cartesian,Cartesian_stretched,spherical)
465! e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) + particles_eta*current(1)
466! e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) + particles_eta*current(2)
467! e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) + particles_eta*current(3)
468! case (cylindrical)
469! e(r_) = -vfluid(phi_)*b(z_)+vfluid(z_)*b(phi_) + particles_eta*current(r_)
470! e(phi_) = vfluid(r_)*b(z_)-vfluid(z_)*b(r_) + particles_eta*current(phi_)
471! e(z_) = -vfluid(r_)*b(phi_)+vfluid(phi_)*b(r_) + particles_eta*current(z_)
472! end select
473! if (particles_etah > zero) then
474! call interpolate_var(igrid,ixG^LL,ixM^LL,ps(igrid)%w(ixG^T,1),ps(igrid)%x,xpart,rho)
475! if (time_advance) then
476! td = (particle_time - global_time) / dt
477! call interpolate_var(igrid,ixG^LL,ixM^LL,pso(igrid)%w(ixG^T,1),ps(igrid)%x,xpart,rhoold)
478! rho = rhoold * (1.d0-td) + rho * td
479! end if
480! select case (coordinate)
481! case (Cartesian,Cartesian_stretched,spherical)
482! e(1) = e(1) + particles_etah/rho * (current(2)*b(3) - current(3)*b(2))
483! e(2) = e(2) + particles_etah/rho * (-current(1)*b(3) + current(3)*b(1))
484! e(3) = e(3) + particles_etah/rho * (current(1)*b(2) - current(2)*b(1))
485! case (cylindrical)
486! e(r_) = e(r_) + particles_etah/rho * (current(phi_)*b(z_) - current(z_)*b(phi_))
487! e(phi_) = e(phi_) + particles_etah/rho * (-current(r_)*b(z_) + current(z_)*b(r_))
488! e(z_) = e(z_) + particles_etah/rho * (current(r_)*b(phi_) - current(phi_)*b(r_))
489! end select
490! end if
491
492 ! Payload update
493 ! Lorentz factor
494 if (mynpayload > 0) then
495 call get_lfac(upart,lfac)
496 mypayload(1) = lfac
497 end if
498
499 ! current gyroradius
500 if (mynpayload > 1) then
501 call cross(upart,b,tmp)
502 tmp = tmp / sqrt(sum(b(:)**2))
503 mypayload(2) = mpart/abs(qpart)*sqrt(sum(tmp(:)**2)) / sqrt(sum(b(:)**2))
504 end if
505
506 ! magnetic moment
507 if (mynpayload > 2) then
508 mypayload(3) = mpart*sum(tmp(:)**2)/(2.0d0*sqrt(sum(b(:)**2)))
509 end if
510
511 ! e.b
512 if (mynpayload > 3) then
513 mypayload(4) = sum(e(:)*b(:))
514 end if
515
516 end subroutine lorentz_update_payload
517
518 function lorentz_get_particle_dt(partp, end_time) result(dt_p)
520 use mod_geometry
521 type(particle_ptr), intent(in) :: partp
522 double precision, intent(in) :: end_time
523 double precision :: dt_p
524 double precision,dimension(ndir) :: b,v
525 double precision :: lfac,absb,dt_cfl
526 double precision :: tout
527 double precision, parameter :: cfl = 0.5d0
528 integer :: ipart, iipart, nout
529
530 if (const_dt_particles > 0) then
531 dt_p = const_dt_particles
532 return
533 end if
534
535 call get_vec(bp, partp%igrid,partp%self%x,partp%self%time,b)
536 absb = sqrt(sum(b(:)**2))
537 call get_lfac(partp%self%u,lfac)
538
539 ! CFL timestep
540 ! make sure we step only one cell at a time:
541 v(:) = abs(partp%self%u(:) / lfac)
542
543! ! convert to angular velocity:
544! if(coordinate ==cylindrical.and.phi_>0) then
545! v(phi_) = abs(v(phi_)/partp%self%x(r_))
546! end if
547
548 dt_cfl = min(bigdouble, &
549 {rnode(rpdx^d_,partp%igrid)/max(v(^d), smalldouble)})
550
551 if(coordinate ==cylindrical.and.phi_>0) then
552 ! phi-momentum leads to radial velocity:
553 if(phi_ .gt. ndim) dt_cfl = min(dt_cfl, &
554 sqrt(rnode(rpdx1_,partp%igrid)/partp%self%x(r_)) &
555 / v(phi_))
556 ! limit the delta phi of the orbit (just for aesthetic reasons):
557 dt_cfl = min(dt_cfl,0.1d0/max(v(phi_), smalldouble))
558 ! take some care at the axis:
559 dt_cfl = min(dt_cfl,(partp%self%x(r_)+smalldouble)/max(v(r_), smalldouble))
560 end if
561
562 dt_cfl = dt_cfl * cfl
563
564 ! bound by gyro-rotation:
565 dt_p = abs( dtheta * partp%self%m * lfac &
566 / (partp%self%q * absb) )
567
568 dt_p = min(dt_p, dt_cfl)
569
570 ! Make sure we don't advance beyond end_time
571 call limit_dt_endtime(end_time - partp%self%time, dt_p)
572
573 end function lorentz_get_particle_dt
574
575end 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.
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
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