10 integer,
parameter :: Boris=1, vay=2, hc=3, lm=4
21 if(physics_type/=
'mhd')
call mpistop(
"Lorentz particles need magnetic field!")
22 if(
ndir/=3)
call mpistop(
"Lorentz particles need ndir=3!")
61 case(
'HC',
'hc',
'higueracary')
63 case(
'LM',
'lm',
'lapentamarkidis')
76 integer :: n, idir, igrid, ipe_particle, nparticles_local
77 double precision :: lfac
95 rrd(n,idir) =
rng%unif_01()
99 {^
d&x(^
d,n) = xprobmin^
d + rrd(n+1,^
d) * (xprobmax^
d - xprobmin^
d)\}
121 if (ipe_particle ==
mype)
then
132 nparticles_local = nparticles_local + 1
148 call lorentz_update_payload(igrid,ps(igrid)%w,pso(igrid)%w,ps(igrid)%x,x(:,n),v(:,n)*lfac,q(n),m(n),defpayload,
ndefpayload,0.d0)
151 call usr_update_payload(igrid,ps(igrid)%w,pso(igrid)%w,ps(igrid)%x,x(:,n),v(:,n)*lfac,q(n),m(n),usrpayload,
nusrpayload,0.d0)
166 integer :: igrid, iigrid, idir, idim
167 double precision,
dimension(ixG^T,1:ndir) :: beta
168 double precision,
dimension(ixG^T,1:nw) :: w,wold
169 double precision :: current(ixG^T,7-2*ndir:3)
171 double precision,
dimension(ixG^T,1:ndir) :: vE, bhat
172 double precision,
dimension(ixG^T) :: kappa, kappa_B, absB, tmp
176 do iigrid=1,igridstail; igrid=igrids(iigrid);
177 w(ixg^t,1:nw) = ps(igrid)%w(ixg^t,1:nw)
178 call phys_to_primitive(ixg^
ll,ixg^
ll,w,ps(igrid)%x)
180 gridvars(igrid)%w(ixg^t,
vp(:)) = w(ixg^t,iw_mom(:))
184 w(ixg^t,1:nw) = pso(igrid)%w(ixg^t,1:nw)
185 call phys_to_primitive(ixg^
ll,ixg^
ll,w,ps(igrid)%x)
186 gridvars(igrid)%wold(ixg^t,
vp(:)) = w(ixg^t,iw_mom(:))
197 double precision,
intent(in) :: end_time
198 double precision :: defpayload(ndefpayload)
199 double precision :: usrpayload(nusrpayload)
200 integer :: ipart, iipart
201 double precision :: lfac, q, m, dt_p, cosphi, sinphi, phi1, phi2, r, re
202 double precision,
dimension(ndir) :: b, e, emom, uminus, t_geom, s, udash, tmp, uplus, xcart1, xcart2, ucart2, radmom, vfluid, current
224 e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) +
particles_eta*current(1)
225 e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) +
particles_eta*current(2)
226 e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) +
particles_eta*current(3)
242 particle(ipart)%payload(1:ndefpayload) = defpayload
257 double precision,
intent(in) :: e(ndir), b(ndir), q, m, dtp
258 double precision,
intent(inout) :: xpart(ndim), upart(ndir)
259 double precision :: lfac, cosphi, sinphi, phi1, phi2, r, re, sigma
260 double precision,
dimension(ndir) :: emom, uprime, tau, s, tmp, uplus, xcart1, xcart2, ucart2, radmom
261 double precision,
dimension(ndir) :: upartk, vbar, Fk, C1, C2, dupartk
262 double precision :: abserr, tol, lfack, J11, J12, J13, J21, J22, J23, J31, J32, J33
263 double precision :: iJ11, iJ12, iJ13, iJ21, iJ22, iJ23, iJ31, iJ32, iJ33, Det
279 emom = q * e * dtp /(2.0d0 * m)
293 uprime = upart + emom + radmom
296 tau = q * b * dtp / (2.0d0 * lfac * m)
297 s = 2.0d0 * tau / (1.0d0+sum(tau(:)**2))
299 call cross(uprime,tau,tmp)
300 call cross(uprime+tmp,s,tmp)
315 upart = uplus + emom + radmom
321 emom = q * e * dtp /(2.0d0 * m)
336 uprime = upart + emom + radmom
339 tau = q * b * dtp / (2.0d0 * lfac * m)
340 s = 2.0d0 * tau / (1.0d0+sum(tau(:)**2))
342 call cross(uprime,tau,tmp)
343 call cross(uprime+tmp,s,tmp)
357 upart = uplus + emom + radmom
364 xcart1(1) = xpart(
r_) * cosphi
365 xcart1(2) = xpart(
r_) * sinphi
366 xcart1(3) = xpart(
z_)
368 ucart2(1) = cosphi * upart(
r_) - sinphi * upart(
phi_)
369 ucart2(2) = cosphi * upart(
phi_) + sinphi * upart(
r_)
370 ucart2(3) = upart(
z_)
373 xcart2(1:ndir) = xcart1(1:ndir) &
374 + dtp * ucart2(1:ndir)/lfac
377 phi2 = atan2(xcart2(2),xcart2(1))
378 if(phi2 .lt. 0.0d0) phi2 = 2.0d0*dpi + phi2
379 r = sqrt(xcart2(1)**2 + xcart2(2)**2)
382 xpart(
z_) = xcart2(3)
386 cosphi = cos(phi2-phi1)
387 sinphi = sin(phi2-phi1)
390 upart(
r_) = cosphi * tmp(
r_) + sinphi * tmp(
phi_)
391 upart(
phi_) = cosphi * tmp(
phi_) - sinphi * tmp(
r_)
395 call mpistop(
"Boris particle pusher incompatible with the chosen geometry")
408 emom = q * e * dtp /(2.0d0 * m)
409 tau = q * b * dtp / (2.0d0 * m)
411 call cross(upart,tau,tmp)
412 uprime = upart + 2.d0*emom + tmp/lfac
415 sigma = lfac**2 - sum(tau(:)*tau(:))
416 lfac = sqrt((sigma + sqrt(sigma**2 &
417 + 4.d0 * (sum(tau(:)*tau(:)) + sum(uprime(:)*tau(:)/
c_norm)**2))) / 2.d0)
419 call cross(uprime,tau,tmp)
420 upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / (1.d0+sum(tau(:)*tau(:))/lfac**2)
423 call mpistop(
"Vay particle pusher incompatible with the chosen geometry")
436 emom = q * e * dtp /(2.0d0 * m)
437 tau = q * b * dtp / (2.0d0 * m)
438 uprime = upart + emom
441 sigma = lfac**2 - sum(tau(:)*tau(:))
442 lfac = sqrt((sigma + sqrt(sigma**2 &
443 + 4.d0 * (sum(tau(:)*tau(:)) + sum(uprime(:)*tau(:)/
c_norm)**2))) / 2.d0)
445 call cross(uprime,tau,tmp)
446 upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / (1.d0+sum(tau(:)*tau(:))/lfac**2) &
450 call mpistop(
"Higuera-Cary particle pusher incompatible with the chosen geometry")
471 do while(abserr > tol .and. nk < nkmax)
476 vbar = (upart + upartk) / (lfac + lfack)
477 call cross(vbar,b,tmp)
480 fk = upartk - upart - q*dtp/m * (e + tmp)
483 c1 = (lfack + lfac - upartk(1:ndim) / lfack /
c_norm**2 * (upartk + upart)) / (lfack + lfac)**2
484 c2 = - upartk / lfack /
c_norm**2 / (lfack + lfac)**2
487 j11 = 1. - q*dtp/m * (c2(1) * (upartk(2) + upart(2)) * b(3) - c2(1) * (upartk(3) + upart(3)) * b(2))
488 j12 = - q*dtp/m * (c1(2) * b(3) - c2(2) * (upartk(3) + upart(3)) * b(2))
489 j13 = - q*dtp/m * (c2(3) * (upartk(2) + upart(2)) * b(3) - c1(3) * b(2))
490 j21 = - q*dtp/m * (- c1(1) * b(3) + c2(1) * (upartk(3) + upart(3)) * b(1))
491 j22 = 1. - q*dtp/m * (- c2(2) * (upartk(1) + upart(1)) * b(3) + c2(2) * (upartk(3) + upart(3)) * b(1))
492 j23 = - q*dtp/m * (- c2(3) * (upartk(1) + upart(1)) * b(3) + c1(3) * b(1))
493 j31 = - q*dtp/m * (c1(1) * b(2) - c2(1) * (upartk(2) + upart(2)) * b(1))
494 j32 = - q*dtp/m * (c2(2) * (upartk(1) + upart(1)) * b(2) - c1(2) * b(1))
495 j33 = 1. - q*dtp/m * (c2(3) * (upartk(1) + upart(1)) * b(2) - c2(3) * (upartk(2) + upart(2)) * b(1))
498 det = j11*j22*j33 + j21*j32*j13 + j31*j12*j23 - j11*j32*j23 - j31*j22*j13 - j21*j12*j33
499 ij11 = (j22*j33 - j23*j32) / det
500 ij12 = (j13*j32 - j12*j33) / det
501 ij13 = (j12*j23 - j13*j22) / det
502 ij21 = (j23*j31 - j21*j33) / det
503 ij22 = (j11*j33 - j13*j31) / det
504 ij23 = (j13*j21 - j11*j23) / det
505 ij31 = (j21*j32 - j22*j31) / det
506 ij32 = (j12*j31 - j11*j32) / det
507 ij33 = (j11*j22 - j12*j21) / det
510 dupartk(1) = - (ij11 * fk(1) + ij12 * fk(2) + ij13 * fk(3))
511 dupartk(2) = - (ij21 * fk(1) + ij22 * fk(2) + ij23 * fk(3))
512 dupartk(3) = - (ij31 * fk(1) + ij32 * fk(2) + ij33 * fk(3))
515 upartk=upartk+dupartk
516 abserr=sqrt(sum(dupartk(:)*dupartk(:)))
525 call mpistop(
"Lapenta-Markidis particle pusher incompatible with the chosen geometry")
533 subroutine lorentz_update_payload(igrid,w,wold,xgrid,xpart,upart,qpart,mpart,mypayload,mynpayload,particle_time)
535 integer,
intent(in) :: igrid,mynpayload
536 double precision,
intent(in) :: w(ixG^T,1:nw),wold(ixG^T,1:nw)
537 double precision,
intent(in) :: xgrid(ixG^T,1:ndim),xpart(1:ndir),upart(1:ndir),qpart,mpart,particle_time
538 double precision,
intent(out) :: mypayload(mynpayload)
539 double precision :: b(3), e(3), tmp(3), lfac, vfluid(3), current(3)
541 call get_vec(
bp, igrid, xpart,particle_time,b)
542 call get_vec(
vp, igrid, xpart,particle_time,vfluid)
543 call get_vec(
jp, igrid, xpart,particle_time,current)
544 e(1) = -vfluid(2)*b(3)+vfluid(3)*b(2) +
particles_eta*current(1)
545 e(2) = vfluid(1)*b(3)-vfluid(3)*b(1) +
particles_eta*current(2)
546 e(3) = -vfluid(1)*b(2)+vfluid(2)*b(1) +
particles_eta*current(3)
550 if (mynpayload > 0)
then
556 if (mynpayload > 1)
then
557 call cross(upart,b,tmp)
558 tmp = tmp / sqrt(sum(b(:)**2))
559 mypayload(2) = mpart/abs(qpart)*sqrt(sum(tmp(:)**2)) / sqrt(sum(b(:)**2))
563 if (mynpayload > 2)
then
564 mypayload(3) = mpart*sum(tmp(:)**2)/(2.0d0*sqrt(sum(b(:)**2)))
568 if (mynpayload > 3)
then
569 mypayload(4) = sum(e(:)*b(:))
578 double precision,
intent(in) :: end_time
579 double precision :: dt_p
580 integer :: ipart, iipart, nout
581 double precision,
dimension(ndir) :: b,v
582 double precision :: lfac,absb,dt_cfl
583 double precision :: tout
584 double precision,
parameter :: cfl = 0.5d0
591 call get_vec(
bp, partp%igrid,partp%self%x,partp%self%time,b)
592 absb = sqrt(sum(b(:)**2))
597 v(:) = abs(partp%self%u(:) / lfac)
604 dt_cfl = min(bigdouble, &
609 if(
phi_ .gt.
ndim) dt_cfl = min(dt_cfl, &
610 sqrt(
rnode(rpdx1_,partp%igrid)/partp%self%x(
r_)) &
613 dt_cfl = min(dt_cfl,0.1d0/max(v(
phi_), smalldouble))
615 dt_cfl = min(dt_cfl,(partp%self%x(
r_)+smalldouble)/max(v(
r_), smalldouble))
618 dt_cfl = dt_cfl * cfl
621 dt_p = abs(
dtheta * partp%self%m * lfac &
622 / (partp%self%q * absb) )
624 dt_p = min(dt_p, dt_cfl)
subroutine mpistop(message)
Exit MPI-AMRVAC with an error message.
Module with geometry-related routines (e.g., divergence, curl)
integer, parameter cartesian
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.
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 r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
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.
integer ngridvars
Number of variables for grid field.
integer nusrpayload
Number of user-defined payload variables for a particle.
double precision particles_eta
Resistivity.
pure subroutine get_lfac(u, lfac)
Get Lorentz factor from relativistic momentum.
subroutine find_particle_ipe(x, igrid_particle, ipe_particle)
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 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.
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
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, dimension(:), allocatable jp
Variable index for current.
Particle mover with Newtonian/relativistic Boris scheme for Lorentz dynamics By Jannis Teunissen,...
double precision function lorentz_get_particle_dt(partp, end_time)
subroutine lorentz_kick(xpart, upart, e, b, q, m, dtp)
Momentum update subroutine for full Lorentz dynamics.
subroutine lorentz_fill_gridvars
subroutine, public lorentz_init()
subroutine lorentz_integrate_particles(end_time)
Relativistic particle integrator.
subroutine lorentz_update_payload(igrid, w, wold, xgrid, xpart, upart, qpart, mpart, mypayload, mynpayload, particle_time)
Update payload subroutine.
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