Skip to content
Snippets Groups Projects
processing_mod.F90 20.54 KiB
MODULE processing
   USE prec_const,  ONLY: xp, imagu, SQRT2, SQRT3, onetwelfth, twothird
   USE grid,        ONLY: &
      local_na, local_np, local_nj, local_nky, local_nkx, local_nz, Ngz,Ngj,Ngp,nzgrid, &
      parray,pmax,ip0, iodd, ieven, total_nz, &
      CONTAINSp0,ip1,CONTAINSp1,ip2,CONTAINSp2,ip3,CONTAINSp3,&
      jarray,jmax,ij0, dmax,&
      kyarray, AA_y,&
      kxarray, AA_x,&
      zarray, zweights_SR, ieven, iodd, inv_deltaz,&
      kroneck_p0, kroneck_p1
   USE fields,           ONLY: moments, phi, psi
   USE array,            ONLY : kernel, nadiab_moments, &
      ddz_napj, ddzND_Napj, interp_napj,&
      dens, upar, uper, Tpar, Tper, temp
   USE geometry,         ONLY: Jacobian, iInt_Jacobian
   USE time_integration, ONLY: updatetlevel
   USE calculus,         ONLY: simpson_rule_z, grad_z, grad_z_5D, grad_z2, grad_z4, grad_z4_5D, interp_z
   USE model,            ONLY: EM, beta, HDz_h
   USE species,          ONLY: tau,q_tau,q_o_sqrt_tau_sigma,sqrt_tau_o_sigma
   USE parallel,         ONLY: num_procs_ky, rank_ky, comm_ky
   USE mpi
   implicit none

   REAL(xp), PUBLIC, ALLOCATABLE, DIMENSION(:), PROTECTED :: pflux_x, gflux_x
   REAL(xp), PUBLIC, ALLOCATABLE, DIMENSION(:), PROTECTED :: hflux_x
   INTEGER :: ierr
   PUBLIC :: init_process
   PUBLIC :: compute_nadiab_moments, compute_gradients_z, compute_interp_z
   PUBLIC :: compute_density, compute_upar, compute_uperp
   PUBLIC :: compute_Tpar, compute_Tperp, compute_fluid_moments
   PUBLIC :: compute_radial_transport
   PUBLIC :: compute_radial_heatflux
   PUBLIC :: compute_Napjz_spectrum
CONTAINS

   SUBROUTINE init_process
      USE grid,       ONLY: local_na
      IMPLICIT NONE
      ALLOCATE( pflux_x(local_na))
      ALLOCATE( gflux_x(local_na))
      ALLOCATE( hflux_x(local_na))
   END SUBROUTINE init_process
   
!------------------------------ HIGH FREQUENCY ROUTINES -------------
! The following routines (nadiab computing, interp and grads) must be
! as fast as possible since they are called every RK step
   ! evaluate the non-adiabatique ion moments
   !
   ! n_{pi} = N^{pj} + kernel(j) /tau_i phi delta_p0
   !
   SUBROUTINE compute_nadiab_moments
      IMPLICIT NONE
      INTEGER :: ia,ij
      !non adiab moments
      ! default : same as moments
      nadiab_moments(:,:,:,:,:,:) = moments(:,:,:,:,:,:,updatetlevel)
      ! add phi and psi contribution
      IF (CONTAINSp0) THEN
         DO ij=1,local_nj+ngj
         DO ia = 1,local_na
            nadiab_moments(ia,ip0,ij,:,:,:) = moments(ia,ip0,ij,:,:,:,updatetlevel) &
            +q_tau(ia)*kernel(ia,ij,:,:,:,ieven)*phi(:,:,:)
         ENDDO 
         ENDDO
      ENDIF
      IF (CONTAINSp1 .AND. (beta .GT. 0)) THEN
         DO ij=1,local_nj+ngj
         DO ia = 1,local_na
            nadiab_moments(ia,ip1,ij,:,:,:) = moments(ia,ip1,ij,:,:,:,updatetlevel) &
               -q_o_sqrt_tau_sigma(ia)*kernel(ia,ij,:,:,:,iodd)*psi(:,:,:)
         ENDDO 
         ENDDO
      ENDIF
   END SUBROUTINE compute_nadiab_moments

   ! ! z grid gradients
   SUBROUTINE compute_gradients_z
      IMPLICIT NONE
      INTEGER :: eo, p_int, ia,ip,ij,iky,ikx
      COMPLEX(xp), DIMENSION(local_nz+ngz) :: f_in
      COMPLEX(xp), DIMENSION(local_nz)     :: f_out
   IF(total_nz .GT. 4) THEN
      DO ikx = 1,local_nkx
      DO iky = 1,local_nky
      DO ij = 1,local_nj+ngj
      DO ip = 1,local_np+ngp
      DO ia = 1,local_na
         IF(nzgrid .GT. 1) THEN
            p_int = parray(ip+ngp/2)
            eo    = MODULO(p_int,2)+1 ! Indicates if we are on even or odd z grid
         ELSE
            eo = 0
         ENDIF
         ! Compute z first derivative
         f_in = nadiab_moments(ia,ip,ij,iky,ikx,:)
         CALL   grad_z(eo,local_nz,ngz,inv_deltaz,f_in,f_out)
         ddz_napj(ia,ip,ij,iky,ikx,:) = f_out
         ! Parallel numerical diffusion
         IF (.NOT. HDz_h) &
            f_in = moments(ia,ip,ij,iky,ikx,:,updatetlevel)
         CALL  grad_z4(local_nz,ngz,inv_deltaz,f_in,f_out)
         ! get output
         ddzND_Napj(ia,ip,ij,iky,ikx,:) = f_out
      ENDDO
      ENDDO
      ENDDO
      ENDDO
      ENDDO
   ELSE ! 2D Z-pinch
      ddz_napj   = 0._xp
      ddzND_Napj = 0._xp
   ENDIF
   END SUBROUTINE compute_gradients_z

      ! z grid interpolation
   SUBROUTINE compute_interp_z
      IMPLICIT NONE
      INTEGER :: eo, ia,ip,ij,iky,ikx,iz
      COMPLEX(xp), DIMENSION(local_nz+ngz) :: f_in
      COMPLEX(xp), DIMENSION(local_nz)     :: f_out
      IF(nzgrid .GT. 1) THEN
         DO ikx = 1,local_nkx
         DO iky = 1,local_nky
         DO ij = 1,local_nj+ngj
         DO ip = 1,local_np+ngp
         DO ia = 1,local_na
            ! Compute even odd grids interpolation
            f_in = nadiab_moments(ia,ip,ij,iky,ikx,:)
            CALL interp_z(eo,local_nz,ngz,f_in,f_out)
            DO iz = 1,local_nz
               interp_napj(ia,ip,ij,iky,ikx,iz) = f_out(iz)
            ENDDO
         ENDDO
         ENDDO
         ENDDO
         ENDDO
         ENDDO
      ELSE
         interp_napj(:,:,:,:,:,1:local_nz) = nadiab_moments(:,:,:,:,:,(1+ngz/2):(local_nz+ngz/2))
      ENDIF
   END SUBROUTINE compute_interp_z

   !--------------------- LOW FREQUENCY PROCESSING ROUTINES -------------------!
   ! The following routines are called by the diagnose routine every nsave3D steps 
   ! (does not need to be optimized)
   ! 1D diagnostic to compute the average radial particle transport <n_a v_ExB_x>_xyz
   SUBROUTINE compute_radial_transport
      IMPLICIT NONE
      COMPLEX(xp) :: pflux_local, gflux_local, integral
      REAL(xp)    :: buffer(2)
      INTEGER     :: i_, root, iky, ikx, ia, iz, in, izi, ini
      COMPLEX(xp), DIMENSION(local_nz) :: integrant
      DO ia = 1,local_na
         pflux_local = 0._xp ! particle flux
         gflux_local = 0._xp ! gyrocenter flux
         integrant   = 0._xp ! auxiliary variable for z integration
         !!---------- Gyro center flux (drift kinetic) ------------
         ! Electrostatic part
         IF(CONTAINSp0) THEN
            DO iz = 1,local_nz
            izi = iz + ngz/2 !interior index for ghosted arrays
            DO ikx = 1,local_nkx
            DO iky = 1,local_nky
               integrant(iz) = integrant(iz) &
               +Jacobian(izi,ieven)*moments(ia,ip0,ij0,iky,ikx,izi,updatetlevel)&
               *imagu*kyarray(iky)*CONJG(phi(iky,ikx,izi))
            ENDDO
            ENDDO
            ENDDO
         ENDIF
         ! Electromagnetic part
         IF( EM .AND. CONTAINSp1 ) THEN
            DO iz = 1,local_nz ! we take interior points only
            izi = iz + ngz/2 !interior index for ghosted arrays
            DO ikx = 1,local_nkx
            DO iky = 1,local_nky
               integrant(iz) = integrant(iz)&
                  -Jacobian(izi,iodd)*sqrt_tau_o_sigma(ia)*moments(ia,ip1,ij0,iky,ikx,izi,updatetlevel)&
                  *imagu*kyarray(iky)*CONJG(psi(iky,ikx,izi))
            ENDDO
            ENDDO
            ENDDO
         ENDIF
         ! Integrate over z
         call simpson_rule_z(local_nz,zweights_SR,integrant,integral)
         ! Get process local gyrocenter flux with a factor two to account for the negative ky modes
         gflux_local = 2._xp*integral*iInt_Jacobian
         !
         !!---------- Particle flux (gyrokinetic) ------------
         integrant   = 0._xp ! reset auxiliary variable
         ! Electrostatic part
         IF(CONTAINSp0) THEN
            DO iz = 1,local_nz ! we take interior points only
            izi = iz + ngz/2 !interior index for ghosted arrays
            DO ikx = 1,local_nkx
            DO iky = 1,local_nky
            DO in = 1, local_nj
            ini = in + ngj/2 !interior index for ghosted arrays
               integrant(iz) = integrant(iz)+ &
                  Jacobian(izi,ieven)*moments(ia,ip0,ini,iky,ikx,izi,updatetlevel)&
                  *imagu*kyarray(iky)*kernel(ia,ini,iky,ikx,izi,ieven)*CONJG(phi(iky,ikx,izi))
            ENDDO
            ENDDO
            ENDDO
            ENDDO
         ENDIF
         ! Electromagnetic part
         IF( EM .AND. CONTAINSp1 ) THEN
            DO iz = 1,local_nz ! we take interior points only
            izi = iz + ngz/2 !interior index for ghosted arrays
            DO ikx = 1,local_nkx
            DO iky = 1,local_nky
            DO in = 1, local_nj
            ini = in + ngj/2 !interior index for ghosted arrays
                  integrant(iz) = integrant(iz) - &
                  Jacobian(izi,iodd)*sqrt_tau_o_sigma(ia)*moments(ia,ip1,ini,iky,ikx,izi,updatetlevel)&
                  *imagu*kyarray(iky)*kernel(ia,ini,iky,ikx,izi,iodd)*CONJG(psi(iky,ikx,izi))
            ENDDO
            ENDDO
            ENDDO
            ENDDO
         ENDIF
         ! Integrate over z
         call simpson_rule_z(local_nz,zweights_SR,integrant,integral)
         ! Get process local particle flux with a factor two to account for the negative ky modes
         pflux_local = 2._xp*integral*iInt_Jacobian
         !!!!---------- Sum over all processes ----------
         buffer(1) = REAL(gflux_local,xp)
         buffer(2) = REAL(pflux_local,xp)
         root = 0
         !Gather manually among the rank_p=0 processes and perform the sum
         gflux_x(ia) = 0
         pflux_x(ia) = 0
         IF (num_procs_ky .GT. 1) THEN
            !! Everyone sends its local_sum to root = 0
            IF (rank_ky .NE. root) THEN
               CALL MPI_SEND(buffer, 2 , MPI_DOUBLE_PRECISION, root, 1234, comm_ky, ierr)
            ELSE
               ! Recieve from all the other processes
               DO i_ = 0,num_procs_ky-1
                  IF (i_ .NE. rank_ky) &
                     CALL MPI_RECV(buffer, 2 , MPI_DOUBLE_PRECISION, i_, 1234, comm_ky, MPI_STATUS_IGNORE, ierr)
                  gflux_x(ia) = gflux_x(ia) + buffer(1)
                  pflux_x(ia) = pflux_x(ia) + buffer(2)
               ENDDO
            ENDIF
         ELSE
            gflux_x(ia) = REAL(gflux_local,xp)
            pflux_x(ia) = REAL(pflux_local,xp)
         ENDIF
      ENDDO
   END SUBROUTINE compute_radial_transport

! 1D diagnostic to compute the average radial particle heatflux <T_i v_ExB_x>_xyz
   SUBROUTINE compute_radial_heatflux
      IMPLICIT NONE
      COMPLEX(xp) :: hflux_local, integral
      REAL(xp)    :: buffer(2), n_xp
      INTEGER     :: i_, root, in, ia, iky, ikx, iz, izi, ini
      COMPLEX(xp), DIMENSION(local_nz) :: integrant        ! charge density q_a n_a
      DO ia = 1,local_na
         hflux_local = 0._xp ! heat flux
         integrant   = 0._xp ! z integration auxiliary variable
         !!----------------ELECTROSTATIC CONTRIBUTION---------------------------
         IF(CONTAINSp0 .AND. CONTAINSp2) THEN
            ! Loop to compute gamma_kx = sum_ky sum_j -i k_z Kernel_j Na00 * phi
            DO iz = 1,local_nz ! we take interior points only
            izi = iz + ngz/2 !interior index for ghosted arrays
            DO ikx = 1,local_nkx
            DO iky = 1,local_nky
            DO in = 1, local_nj
            ini  = in+ngj/2 !interior index for ghosted arrays
            n_xp = jarray(ini)
               integrant(iz) = integrant(iz) &
                  -Jacobian(izi,ieven)*tau(ia)*imagu*kyarray(iky)*phi(iky,ikx,izi)&
                  *kernel(ia,ini,iky,ikx,izi,ieven)*CONJG(&
                              0.5_xp*SQRT2*moments(ia,ip2,ini  ,iky,ikx,izi,updatetlevel)&
                  +(2._xp*n_xp + 1.5_xp)*moments(ia,ip0,ini  ,iky,ikx,izi,updatetlevel)&
                           -(n_xp+1._xp)*moments(ia,ip0,ini+1,iky,ikx,izi,updatetlevel)&
                                    -n_xp*moments(ia,ip0,ini-1,iky,ikx,izi,updatetlevel))
            ENDDO
            ENDDO
            ENDDO
            ENDDO
         ELSEIF(CONTAINSp0) THEN
            ERROR STOP "Degrees p=0 and p=2 should be owned by the same process"
         ENDIF
         IF(EM .AND. CONTAINSp1 .AND. CONTAINSp3) THEN
            !!----------------ELECTROMAGNETIC CONTRIBUTION--------------------
            DO iz  = 1,local_nz
            izi = iz + ngz/2 !interior index for ghosted arrays
            DO ikx = 1,local_nkx
            DO iky = 1,local_nky
            DO in = 1, local_nj
            ini = in + ngj/2 !interior index for ghosted arrays
            n_xp = jarray(ini)
               integrant(iz) = integrant(iz) &
                     +Jacobian(izi,iodd)*tau(ia)*sqrt_tau_o_sigma(ia)*imagu*kyarray(iky)*CONJG(psi(iky,ikx,izi))&
                  *kernel(ia,ini,iky,ikx,izi,iodd)*(&
                  0.5_xp*SQRT2*SQRT3*moments(ia,ip3,ini  ,iky,ikx,izi,updatetlevel)&
                              +1.5_xp*moments(ia,ip1,ini  ,iky,ikx,izi,updatetlevel)&
                  +(2._xp*n_xp+1._xp)*moments(ia,ip1,ini  ,iky,ikx,izi,updatetlevel)&
                        -(n_xp+1._xp)*moments(ia,ip1,ini+1,iky,ikx,izi,updatetlevel)&
                                 -n_xp*moments(ia,ip1,ini-1,iky,ikx,izi,updatetlevel))
            ENDDO
            ENDDO
            ENDDO
            ENDDO
         ENDIF
         ! Add polarisation contribution
         ! integrant(iz) = integrant(iz) + tau_i*imagu*ky_&
         ! *CONJG(phi(iky,ikx,iz))*phi(iky,ikx,iz) * HF_phi_correction_operator(iky,ikx,iz)
         ! Integrate over z
         call simpson_rule_z(local_nz,zweights_SR,integrant,integral)
         ! Double it for taking into account the other half plane
         hflux_local = 2._xp*integral*iInt_Jacobian
         buffer(2)   = REAL(hflux_local,xp)
         root = 0
         !Gather manually among the rank_p=0 processes and perform the sum
         hflux_x(ia) = 0
         IF (num_procs_ky .GT. 1) THEN
            !! Everyone sends its local_sum to root = 0
            IF (rank_ky .NE. root) THEN
               CALL MPI_SEND(buffer, 2 , MPI_DOUBLE_PRECISION, root, 1234, comm_ky, ierr)
            ELSE
               ! Recieve from all the other processes
               DO i_ = 0,num_procs_ky-1
                  IF (i_ .NE. rank_ky) &
                     CALL MPI_RECV(buffer, 2 , MPI_DOUBLE_PRECISION, i_, 1234, comm_ky, MPI_STATUS_IGNORE, ierr)
                  hflux_x(ia) = hflux_x(ia) + buffer(2)
               ENDDO
            ENDIF
         ELSE
            hflux_x(ia) = REAL(hflux_local,xp)
         ENDIF
      ENDDO
   END SUBROUTINE compute_radial_heatflux

   SUBROUTINE compute_Napjz_spectrum
      USE fields, ONLY : moments
      USE array,  ONLY : Napjz
      USE time_integration, ONLY : updatetlevel
      IMPLICIT NONE
      REAL(xp), DIMENSION(local_np,local_nj,local_nz) :: local_sum, global_sum, buffer
      INTEGER  :: i_, root, count, ia, ip, ij, iky, ikx, iz
      root = 0
      DO ia=1,local_na
         ! z-moment spectrum
         ! build local sum
         local_sum = 0._xp
         DO iz  = 1,local_nz
         DO ikx = 1,local_nkx
         DO iky = 1,local_nky
         DO ij  = 1,local_nj
         DO ip  = 1,local_np
            local_sum(ip,ij,iz)  = local_sum(ip,ij,iz)  + &
               REAL(moments(ia,ip+Ngp/2,ij+Ngj/2,iky,ikx,iz+Ngz/2,updatetlevel) &
               * CONJG(moments(ia,ip+Ngp/2,ij+Ngj/2,iky,ikx,iz+Ngz/2,updatetlevel)),xp)
         ENDDO
         ENDDO
         ENDDO
         ENDDO
         ENDDO
         ! sum reduction
         buffer     = local_sum
         global_sum = 0._xp
         count = local_np*local_nj*local_nz
         IF (num_procs_ky .GT. 1) THEN
            !! Everyone sends its local_sum to root = 0
            IF (rank_ky .NE. root) THEN
               CALL MPI_SEND(buffer, count , MPI_DOUBLE_PRECISION, root, 5678, comm_ky, ierr)
            ELSE
               ! Recieve from all the other processes
               DO i_ = 0,num_procs_ky-1
                  IF (i_ .NE. rank_ky) &
                     CALL MPI_RECV(buffer, count , MPI_DOUBLE_PRECISION, i_, 5678, comm_ky, MPI_STATUS_IGNORE, ierr)
                  global_sum = global_sum + buffer
               ENDDO
            ENDIF
         ELSE
            global_sum = local_sum
         ENDIF
         Napjz(ia,:,:,:) = global_sum
      ENDDO
   END SUBROUTINE compute_Napjz_spectrum

!_____________________________________________________________________________!
!!!!! FLUID MOMENTS COMPUTATIONS !!!!!
! Compute the 2D particle density for electron and ions (sum over Laguerre)
   SUBROUTINE compute_density
   IMPLICIT NONE
   COMPLEX(xp) :: dens_
   INTEGER :: ia, iz, iky, ikx, ij
   DO ia=1,local_na
   IF ( CONTAINSp0 ) THEN
   ! Loop to compute dens_i = sum_j kernel_j Ni0j at each k
   DO iz = 1,local_nz
   DO iky = 1,local_nky
   DO ikx = 1,local_nkx
      dens_ = 0._xp
      DO ij = 1, local_nj
         dens_ = dens_ + kernel(ia,ij+ngj/2,iky,ikx,iz+ngz/2,ieven) * moments(ia,ip0,ij+ngj/2,iky,ikx,iz+ngz/2,updatetlevel)
      ENDDO
      dens(ia,iky,ikx,iz) = dens_
   ENDDO
   ENDDO
   ENDDO
   ENDIF
   ENDDO
   END SUBROUTINE compute_density

! Compute the 2D particle fluid perp velocity for electron and ions (sum over Laguerre)
   SUBROUTINE compute_uperp
      IMPLICIT NONE
      COMPLEX(xp) :: uperp_
      INTEGER :: ia, iz, iky, ikx, ij
      DO ia=1,local_na
      IF ( CONTAINSp0 ) THEN
      DO iz = 1,local_nz
      DO iky = 1,local_nky
      DO ikx = 1,local_nkx
      uperp_ = 0._xp
      DO ij = 1, local_nj
         uperp_ = uperp_ + kernel(ia,ij+ngj/2,iky,ikx,iz+ngz/2,ieven) *&
            0.5_xp*(moments(ia,ip0,ij+ngj/2,iky,ikx,iz+ngz/2,updatetlevel)&
                     -moments(ia,ip0,ij-1+ngj/2,iky,ikx,iz+ngz/2,updatetlevel))
      ENDDO
      uper(ia,iky,ikx,iz) = uperp_
      ENDDO
      ENDDO
      ENDDO
      ENDIF
      ENDDO
   END SUBROUTINE compute_uperp

! Compute the 2D particle fluid par velocity for electron and ions (sum over Laguerre)
   SUBROUTINE compute_upar
      IMPLICIT NONE
      INTEGER :: ia, iz, iky, ikx, ij
      COMPLEX(xp) :: upar_
      DO ia=1,local_na
      IF ( CONTAINSp1 ) THEN
      DO iz = 1,local_nz
      DO iky = 1,local_nky
      DO ikx = 1,local_nkx
         upar_ = 0._xp
         DO ij = 1, local_nj
            upar_ = upar_ + kernel(ia,ij+ngj/2,iky,ikx,iz+ngz/2,iodd)*moments(ia,ip1,ij+ngj/2,iky,ikx,iz+ngz/2,updatetlevel)
         ENDDO
         upar(ia,iky,ikx,iz) = upar_
      ENDDO
      ENDDO
      ENDDO
      ENDIF
      ENDDO
   END SUBROUTINE compute_upar

! Compute the 2D particle temperature for electron and ions (sum over Laguerre)
   SUBROUTINE compute_tperp
      USE time_integration, ONLY : updatetlevel
      IMPLICIT NONE
      REAL(xp)    :: j_xp
      COMPLEX(xp) :: Tperp_
      INTEGER     :: ia, iz, iky, ikx, ij
      DO ia=1,local_na
      IF ( CONTAINSp0 .AND. CONTAINSp2 ) THEN
      ! Loop to compute T = 1/3*(Tpar + 2Tperp)
      DO iz = 1,local_nz
      DO iky = 1,local_nky
      DO ikx = 1,local_nkx
      Tperp_ = 0._xp
      DO ij = 1, local_nj
         j_xp = jarray(ij+ngj/2)
         Tperp_ = Tperp_ + kernel(ia,ij+ngj/2,iky,ikx,iz+ngz/2,ieven)*&
            ((2_xp*j_xp+1)*moments(ia,ip0,ij  +ngj/2,iky,ikx,iz+ngz/2,updatetlevel)&
                     -j_xp*moments(ia,ip0,ij-1+ngj/2,iky,ikx,iz+ngz/2,updatetlevel)&
                  -(j_xp+1)*moments(ia,ip0,ij+1+ngj/2,iky,ikx,iz+ngz/2,updatetlevel))
      ENDDO
      Tper(ia,iky,ikx,iz) = Tperp_
      ENDDO
      ENDDO
      ENDDO
      ENDIF
      ENDDO
   END SUBROUTINE compute_Tperp

! Compute the 2D particle temperature for electron and ions (sum over Laguerre)
   SUBROUTINE compute_Tpar
      USE time_integration, ONLY : updatetlevel
      IMPLICIT NONE
      REAL(xp)    :: j_xp
      COMPLEX(xp) :: Tpar_
      INTEGER     :: ia, iz, iky, ikx, ij
      DO ia=1,local_na
      IF ( CONTAINSp0 .AND. CONTAINSp0 ) THEN
      ! Loop to compute T = 1/3*(Tpar + 2Tperp)
      DO iz = 1,local_nz
      DO iky = 1,local_nky
      DO ikx = 1,local_nkx
      Tpar_ = 0._xp
      DO ij = 1, local_nj
         j_xp = REAL(ij-1,xp)
         Tpar_  = Tpar_ + kernel(ia,ij+ngj/2,iky,ikx,iz+ngz/2,ieven)*&
            (SQRT2 * moments(ia,ip2,ij+ngj/2,iky,ikx,iz+ngz/2,updatetlevel) &
                     + moments(ia,ip0,ij+ngj/2,iky,ikx,iz+ngz/2,updatetlevel))
      ENDDO
      Tpar(ia,iky,ikx,iz) = Tpar_
      ENDDO
      ENDDO
      ENDDO
      ENDIF
      ENDDO
   END SUBROUTINE compute_Tpar

! Compute the 2D particle fluid moments for electron and ions (sum over Laguerre)
   SUBROUTINE compute_fluid_moments
      IMPLICIT NONE
      CALL compute_density
      CALL compute_upar
      CALL compute_uperp
      CALL compute_Tpar
      CALL compute_Tperp
      ! Temperature
      temp = (Tpar - 2._xp * Tper)/3._xp - dens
   END SUBROUTINE compute_fluid_moments

END MODULE processing