Lorentz_kick Subroutine

private subroutine Lorentz_kick(upart, e, b, q, m, dtp)

Uses

  • proc~~lorentz_kick~~UsesGraph proc~lorentz_kick Lorentz_kick module~mod_geometry mod_geometry proc~lorentz_kick->module~mod_geometry module~mod_global_parameters mod_global_parameters proc~lorentz_kick->module~mod_global_parameters module~mod_comm_lib mod_comm_lib module~mod_geometry->module~mod_comm_lib module~mod_basic_types mod_basic_types module~mod_global_parameters->module~mod_basic_types module~mod_connectivity mod_connectivity module~mod_global_parameters->module~mod_connectivity module~mod_constants mod_constants module~mod_global_parameters->module~mod_constants module~mod_physicaldata mod_physicaldata module~mod_global_parameters->module~mod_physicaldata module~mod_variables mod_variables module~mod_global_parameters->module~mod_variables mpi mpi module~mod_global_parameters->mpi module~mod_variables->module~mod_basic_types

Momentum update subroutine for full Lorentz dynamics

Arguments

Type IntentOptional Attributes Name
double precision, intent(inout) :: upart(ndir)
double precision, intent(in) :: e(ndir)
double precision, intent(in) :: b(ndir)
double precision, intent(in) :: q
double precision, intent(in) :: m
double precision, intent(in) :: dtp

Calls

proc~~lorentz_kick~~CallsGraph proc~lorentz_kick Lorentz_kick proc~cross cross proc~lorentz_kick->proc~cross proc~get_lfac get_lfac proc~lorentz_kick->proc~get_lfac proc~mpistop mpistop proc~cross->proc~mpistop mpi_abort mpi_abort proc~mpistop->mpi_abort

Called by

proc~~lorentz_kick~~CalledByGraph proc~lorentz_kick Lorentz_kick proc~lorentz_integrate_particles Lorentz_integrate_particles proc~lorentz_integrate_particles->proc~lorentz_kick

Source Code

  subroutine Lorentz_kick(upart,e,b,q,m,dtp)
    use mod_global_parameters
    use mod_geometry
    double precision, intent(in)      :: e(ndir), b(ndir), q, m, dtp
    double precision, intent(inout)   :: upart(ndir)
    double precision                  :: lfac, cosphi, sinphi, phi1, phi2, r,&
        re, sigma, td
    double precision, dimension(ndir) :: emom, uprime, tau, s, tmp, uplus,&
        xcart1, xcart2, ucart2, radmom
    double precision, dimension(ndir) :: upartk, vbar, Fk, C1, C2, dupartk
    double precision                  :: abserr, tol, lfack, J11, J12, J13,&
        J21, J22, J23, J31, J32, J33
    double precision                  :: iJ11, iJ12, iJ13, iJ21, iJ22, iJ23,&
        iJ31, iJ32, iJ33, Det
    integer                           :: nk, nkmax

    ! Perform momentum update based on the chosen integrator
    select case(integrator)

    ! Boris integrator (works in Cartesian and cylindrical)
    case(Boris)
      ! Momentum update
      emom = q * e * dtp /(2.0d0 * m)
      uprime = upart + emom
      !!!!!! TODO: Adjust and document losses
!      if (losses) then
!        call get_lfac(particle(ipart)%self%u,lfac)
!        re = abs(q)**2 / (m * const_c**2)
!        call cross(upart,b,tmp)
!        radmom = - third * re**2 * lfac &
!             * ( sum((e(:)+tmp(:)/lfac)**2)  &
!             -  (sum(e(:)*upart(:))/lfac)**2 ) &
!             * particle(ipart)%self%u / m / const_c * dt_p
!        uprime = uprime + radmom
!      end if

      call get_lfac(uprime,lfac)
      tau = q * b * dtp / (2.0d0 * lfac * m)
      s = 2.0d0 * tau / (1.0d0+sum(tau(:)**2))

      call cross(uprime,tau,tmp)
      call cross(uprime+tmp,s,tmp)
      uplus = uprime + tmp

      upart = uplus + emom
      !!!!!! TODO: Adjust and document losses
!      if(losses) then
!        call cross(uplus,b,tmp)
!        radmom = - third * re**2 * lfac &
!             * ( sum((e(:)+tmp(:)/lfac)**2)  &
!             -  (sum(e(:)*uplus(:))/lfac)**2 ) &
!             * uplus / m / const_c * dt_p
!        upart = upart + radmom
!      end if

    ! Vay integrator
    case(Vay)
      call get_lfac(upart,lfac)
      emom = q * e * dtp /(2.0d0 * m)
      tau = q * b * dtp / (2.0d0 * m)

      call cross(upart,tau,tmp)
      uprime = upart + 2.d0*emom + tmp/lfac

      call get_lfac(uprime,lfac)
      sigma = lfac**2 - sum(tau(:)*tau(:))
      lfac = sqrt((sigma + sqrt(sigma**2 + 4.d0 * (sum(tau(:)*tau(:)) + &
         sum(uprime(:)*tau(:)/c_norm)**2))) / 2.d0)
      
      call cross(uprime,tau,tmp)
      upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / &
         (1.d0+sum(tau(:)*tau(:))/lfac**2)

    ! Higuera-Cary integrator
    case(HC)
      call get_lfac(upart,lfac)
      emom = q * e * dtp /(2.0d0 * m)
      tau = q * b * dtp / (2.0d0 * m)
      uprime = upart + emom

      call get_lfac(uprime,lfac)
      sigma = lfac**2 - sum(tau(:)*tau(:))
      lfac = sqrt((sigma + sqrt(sigma**2 + 4.d0 * (sum(tau(:)*tau(:)) + &
         sum(uprime(:)*tau(:)/c_norm)**2))) / 2.d0)
      
      call cross(uprime,tau,tmp)
      upart = (uprime + sum(uprime(:)*tau(:))*tau/lfac**2 + tmp/lfac) / &
         (1.d0+sum(tau(:)*tau(:))/lfac**2) + emom + tmp/lfac

    ! Lapenta-Markidis integrator
    case(LM)
      ! Initialise iteration quantities
      call get_lfac(upart,lfac)
      upartk = upart
      tau(:) = b(:)

      ! START OF THE NONLINEAR CYCLE
      abserr = 1.d0
      tol=1.d-14
      nkmax=10
      nk=0
      do while(abserr > tol .and. nk < nkmax)

        nk=nk+1

        call get_lfac(upartk,lfack)
        vbar = (upart + upartk) / (lfac + lfack)
        call cross(vbar,tau,tmp)

        ! Compute residual vector
        Fk = upartk - upart - q*dtp/m * (e + tmp)

        ! Compute auxiliary coefficients
        C1 = (lfack + lfac - upartk(1:ndim) / lfack / c_norm**2 * (upartk + &
           upart)) / (lfack + lfac)**2
        C2 = - upartk / lfack / c_norm**2 / (lfack + lfac)**2

        ! Compute Jacobian
        J11 = 1. - q*dtp/m * (C2(1) * (upartk(2) + upart(2)) * tau(3) - C2(1) &
           * (upartk(3) + upart(3)) * tau(2))
        J12 = - q*dtp/m * (C1(2) * tau(3) - C2(2) * (upartk(3) + upart(3)) * &
           tau(2))
        J13 = - q*dtp/m * (C2(3) * (upartk(2) + upart(2)) * tau(3) - C1(3) * &
           tau(2))
        J21 = - q*dtp/m * (- C1(1) * tau(3) + C2(1) * (upartk(3) + upart(3)) * &
           tau(1))
        J22 = 1. - q*dtp/m * (- C2(2) * (upartk(1) + upart(1)) * tau(3) + &
           C2(2) * (upartk(3) + upart(3)) * tau(1))
        J23 = - q*dtp/m * (- C2(3) * (upartk(1) + upart(1)) * tau(3) + C1(3) * &
           tau(1))
        J31 = - q*dtp/m * (C1(1) * tau(2) - C2(1) * (upartk(2) + upart(2)) * &
           tau(1))
        J32 = - q*dtp/m * (C2(2) * (upartk(1) + upart(1)) * tau(2) - C1(2) * &
           tau(1))
        J33 = 1. - q*dtp/m * (C2(3) * (upartk(1) + upart(1)) * tau(2) - C2(3) &
           * (upartk(2) + upart(2)) * tau(1))

        ! Compute inverse Jacobian
        Det = J11*J22*J33 + J21*J32*J13 + J31*J12*J23 - J11*J32*J23 - &
           J31*J22*J13 - J21*J12*J33
        iJ11 = (J22*J33 - J23*J32) / Det
        iJ12 = (J13*J32 - J12*J33) / Det
        iJ13 = (J12*J23 - J13*J22) / Det
        iJ21 = (J23*J31 - J21*J33) / Det
        iJ22 = (J11*J33 - J13*J31) / Det
        iJ23 = (J13*J21 - J11*J23) / Det
        iJ31 = (J21*J32 - J22*J31) / Det
        iJ32 = (J12*J31 - J11*J32) / Det
        iJ33 = (J11*J22 - J12*J21) / Det

        ! Compute new upartk = upartk - J^(-1) * F(upartk)
        dupartk(1) = - (iJ11 * Fk(1) + iJ12 * Fk(2) + iJ13 * Fk(3))
        dupartk(2) = - (iJ21 * Fk(1) + iJ22 * Fk(2) + iJ23 * Fk(3))
        dupartk(3) = - (iJ31 * Fk(1) + iJ32 * Fk(2) + iJ33 * Fk(3))

        ! Check convergence
        upartk=upartk+dupartk
        abserr=sqrt(sum(dupartk(:)*dupartk(:)))

      end do
      ! END OF THE NONLINEAR CYCLE

      ! Update velocity
      upart = upartk

    end select

  end subroutine Lorentz_kick