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!")
66 case(
'HC',
'hc',
'higueracary')
68 case(
'LM',
'lm',
'lapentamarkidis')
83 double precision :: lfac
91 integer :: n, idir, igrid, ipe_particle, nparticles_local
102 rrd(n,idir) =
rng%unif_01()
106 {^
d&x(^
d,n) = xprobmin^
d + rrd(n+1,^
d) * (xprobmax^
d - xprobmin^
d)\}
128 if (ipe_particle ==
mype)
then
139 nparticles_local = nparticles_local + 1
155 call lorentz_update_payload(igrid,x(:,n),v(:,n)*lfac,q(n),m(n),defpayload,
ndefpayload,0.d0)
173 subroutine lorentz_fill_gridvars
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
189 end subroutine lorentz_fill_gridvars
192 subroutine lorentz_integrate_particles(end_time)
196 double precision,
intent(in) :: end_time
199 double precision :: lfac, q, m, dt_p
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
215 dt_p = lorentz_get_particle_dt(
particle(ipart), end_time)
223 xpcm = xpc + 0.5d0 * dt_p * upc/lfac
268 call lorentz_kick(upc,ec,bc,q,m,dt_p)
273 xpc = xpcm + 0.5d0 * dt_p * upc/lfac
288 call lorentz_update_payload(igrid,xp,up,q,m,defpayload,
ndefpayload,tp)
297 end subroutine lorentz_integrate_particles
300 subroutine lorentz_kick(upart,e,b,q,m,dtp)
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
318 emom = q * e * dtp /(2.0d0 * m)
319 uprime = upart + emom
333 tau = q * b * dtp / (2.0d0 * lfac * m)
334 s = 2.0d0 * tau / (1.0d0+sum(tau(:)**2))
336 call cross(uprime,tau,tmp)
337 call cross(uprime+tmp,s,tmp)
354 emom = q * e * dtp /(2.0d0 * m)
355 tau = q * b * dtp / (2.0d0 * m)
357 call cross(upart,tau,tmp)
358 uprime = upart + 2.d0*emom + tmp/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)
365 call cross(uprime,tau,tmp)
366 upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / (1.d0+sum(tau(:)*tau(:))/lfac**2)
371 emom = q * e * dtp /(2.0d0 * m)
372 tau = q * b * dtp / (2.0d0 * m)
373 uprime = upart + emom
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)
380 call cross(uprime,tau,tmp)
381 upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / (1.d0+sum(tau(:)*tau(:))/lfac**2) &
396 do while(abserr > tol .and. nk < nkmax)
401 vbar = (upart + upartk) / (lfac + lfack)
402 call cross(vbar,tau,tmp)
405 fk = upartk - upart - q*dtp/m * (e + tmp)
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
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))
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
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))
440 upartk=upartk+dupartk
441 abserr=sqrt(sum(dupartk(:)*dupartk(:)))
451 end subroutine lorentz_kick
454 subroutine lorentz_update_payload(igrid,xpart,upart,qpart,mpart,mypayload,mynpayload,particle_time)
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
462 call get_bfield(igrid, xpart, particle_time, b)
463 call get_efield(igrid, xpart, particle_time, e)
499 if (mynpayload > 0)
then
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))
512 if (mynpayload > 2)
then
513 mypayload(3) = mpart*sum(tmp(:)**2)/(2.0d0*sqrt(sum(b(:)**2)))
517 if (mynpayload > 3)
then
518 mypayload(4) = sum(e(:)*b(:))
521 end subroutine lorentz_update_payload
523 function lorentz_get_particle_dt(partp, end_time)
result(dt_p)
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
540 call get_vec(
bp, partp%igrid,partp%self%x,partp%self%time,b)
541 absb = sqrt(sum(b(:)**2))
546 v(:) = abs(partp%self%u(:) / lfac)
553 dt_cfl = min(bigdouble, &
558 if(
phi_ .gt.
ndim) dt_cfl = min(dt_cfl, &
559 sqrt(
rnode(rpdx1_,partp%igrid)/partp%self%x(
r_)) &
562 dt_cfl = min(dt_cfl,0.1d0/max(v(
phi_), smalldouble))
564 dt_cfl = min(dt_cfl,(partp%self%x(
r_)+smalldouble)/max(v(
r_), smalldouble))
567 dt_cfl = dt_cfl * cfl
570 dt_p = abs(
dtheta * partp%self%m * lfac &
571 / (partp%self%q * absb) )
573 dt_p = min(dt_p, dt_cfl)
578 end function lorentz_get_particle_dt
Module with geometry-related routines (e.g., divergence, curl)
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)
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