Skip to content
Snippets Groups Projects
processing_mod.F90 22.20 KiB
MODULE processing
   USE prec_const,  ONLY: dp, imagu, SQRT2, SQRT3
   USE grid,        ONLY: &
      local_na, local_np, local_nj, local_nky, local_nkx, local_nz, Ngz,Ngj,Ngp,nzgrid, &
      parray,pmax,ip0, iodd, ieven,&
      CONTAINSp0,ip1,CONTAINSp1,ip2,CONTAINSp2,ip3,CONTAINSp3,&
      jarray,jmax,ij0, dmax,&
      kyarray, AA_y,&
      kxarray, AA_x,&
      zarray, deltaz, ieven, iodd, inv_deltaz
   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_z2, grad_z4, interp_z
   USE model,            ONLY: EM, CLOS, beta, HDz_h
   USE species,          ONLY: tau,q_tau,q_o_sqrt_tau_sigma,sqrt_tau_o_sigma
   USE basic,            ONLY: t0_process, t1_process, tc_process
   USE parallel,         ONLY: num_procs_ky, rank_ky, comm_ky
   USE mpi
   implicit none

   REAL(dp), PUBLIC, ALLOCATABLE, DIMENSION(:), PROTECTED :: pflux_x, gflux_x
   REAL(dp), PUBLIC, ALLOCATABLE, DIMENSION(:), PROTECTED :: hflux_x
   INTEGER :: ierr
   PUBLIC :: init_process
   PUBLIC :: compute_nadiab_moments_z_gradients_and_interp
   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

! 1D diagnostic to compute the average radial particle transport <n_a v_ExB_x>_xyz
   SUBROUTINE compute_radial_transport
      IMPLICIT NONE
      COMPLEX(dp) :: pflux_local, gflux_local, integral
      REAL(dp)    :: buffer(2)
      INTEGER     :: i_, root, iky, ikx, ia, iz, in, izi
      COMPLEX(dp), DIMENSION(local_nz) :: integrant
      DO ia = 1,local_na
         pflux_local = 0._dp ! particle flux
         gflux_local = 0._dp ! gyrocenter flux
         integrant   = 0._dp ! 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,deltaz,integrant,integral)
         ! Get process local gyrocenter flux with a factor two to account for the negative ky modes
         gflux_local = 2._dp*integral*iInt_Jacobian

         !
         integrant   = 0._dp ! reset auxiliary variable
         !!---------- Particle flux (gyrokinetic) ------------
         ! 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+ngj/2, local_nj+ngj/2 ! only interior points
                        integrant(iz) = integrant(iz)+ &
                           Jacobian(izi,ieven)*moments(ia,ip0,in,iky,ikx,izi,updatetlevel)&
                           *imagu*kyarray(iky)*kernel(ia,in,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+ngj/2, local_nj+ngj/2 ! only interior points
                        integrant(iz) = integrant(iz) - &
                           Jacobian(izi,iodd)*sqrt_tau_o_sigma(ia)*moments(ia,ip1,in,iky,ikx,izi,updatetlevel)&
                           *imagu*kyarray(iky)*kernel(ia,in,iky,ikx,izi,iodd)*CONJG(psi(iky,ikx,izi))
                     ENDDO
                  ENDDO
               ENDDO
            ENDDO
         ENDIF
         ! Integrate over z
         call simpson_rule_z(local_nz,deltaz,integrant,integral)
         ! Get process local particle flux with a factor two to account for the negative ky modes
         pflux_local = 2._dp*integral*iInt_Jacobian

         !!!!---------- Sum over all processes ----------
         buffer(1) = REAL(gflux_local,dp)
         buffer(2) = REAL(pflux_local,dp)
         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) = gflux_local
            pflux_x(ia) = pflux_local
         ENDIF
      ENDDO
      ! if(my_id .eq. 0) write(*,*) 'pflux_ri = ',pflux_ri
   END SUBROUTINE compute_radial_transport

! 1D diagnostic to compute the average radial particle transport <T_i v_ExB_x>_xyz
   SUBROUTINE compute_radial_heatflux
      IMPLICIT NONE
      COMPLEX(dp) :: hflux_local, integral
      REAL(dp)    :: buffer(2), n_dp
      INTEGER     :: i_, root, in, ia, iky, ikx, iz, izi
      COMPLEX(dp), DIMENSION(local_nz) :: integrant        ! charge density q_a n_a
      DO ia = 1,local_na
         hflux_local = 0._dp ! heat flux
         integrant   = 0._dp ! 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+ngj/2, local_nj+ngj/2 ! only interior points
                        n_dp = jarray(in)
                        integrant(iz) = integrant(iz) &
                           +Jacobian(izi,ieven)*tau(ia)*imagu*kyarray(iky)*CONJG(phi(iky,ikx,izi))&
                           *kernel(ia,in,iky,ikx,izi,ieven)*(&
                                     0.5_dp*SQRT2*moments(ia,ip2,in  ,iky,ikx,izi,updatetlevel)&
                           +(2._dp*n_dp + 1.5_dp)*moments(ia,ip0,in  ,iky,ikx,izi,updatetlevel)&
                                    -(n_dp+1._dp)*moments(ia,ip0,in+1,iky,ikx,izi,updatetlevel)&
                                            -n_dp*moments(ia,ip0,in-1,iky,ikx,izi,updatetlevel))
                     ENDDO
                  ENDDO
               ENDDO
            ENDDO
         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+ngj/2, local_nj+ngj/2 ! only interior points
                        n_dp = jarray(in)
                        integrant(iz) = integrant(iz) &
                           +Jacobian(izi,iodd)*tau(ia)*sqrt_tau_o_sigma(ia)*imagu*kyarray(iky)*CONJG(psi(iky,ikx,izi))&
                           *kernel(ia,in,iky,ikx,izi,iodd)*(&
                           0.5_dp*SQRT2*SQRT3*moments(ia,ip3,in  ,iky,ikx,izi,updatetlevel)&
                                      +1.5_dp*moments(ia,ip1,in  ,iky,ikx,izi,updatetlevel)&
                          +(2._dp*n_dp+1._dp)*moments(ia,ip1,in  ,iky,ikx,izi,updatetlevel)&
                                -(n_dp+1._dp)*moments(ia,ip1,in+1,iky,ikx,izi,updatetlevel)&
                                        -n_dp*moments(ia,ip1,in-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,deltaz,integrant,integral)
         ! Double it for taking into account the other half plane
         hflux_local = 2._dp*integral*iInt_Jacobian
         buffer(2)   = REAL(hflux_local,dp)
         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) = hflux_local
         ENDIF
      ENDDO
   END SUBROUTINE compute_radial_heatflux

   SUBROUTINE compute_nadiab_moments_z_gradients_and_interp
      ! evaluate the non-adiabatique ion moments
      !
      ! n_{pi} = N^{pj} + kernel(j) /tau_i phi delta_p0
      !
      IMPLICIT NONE
      INTEGER :: eo, p_int, j_int, ia,ip,ij,iky,ikx,iz
      COMPLEX(dp), DIMENSION(local_nz+ngz) :: f_in
      COMPLEX(dp), DIMENSION(local_nz)     :: f_out
      CALL cpu_time(t0_process)

      !non adiab moments
      DO iz=1,local_nz+ngz
         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(parray(ip) .EQ. 0) THEN
                           nadiab_moments(ia,ip,ij,iky,ikx,iz) = moments(ia,ip,ij,iky,ikx,iz,updatetlevel) &
                              + q_tau(ia)*kernel(ia,ij,iky,ikx,iz,ieven)*phi(iky,ikx,iz)
                        ELSEIF( (parray(ip) .EQ. 1) .AND. (beta .GT. 0) ) THEN
                           nadiab_moments(ia,ip,ij,iky,ikx,iz) = moments(ia,ip,ij,iky,ikx,iz,updatetlevel) &
                              - q_o_sqrt_tau_sigma(ia)*kernel(ia,ij,iky,ikx,iz,ieven)*psi(iky,ikx,iz)
                        ELSE
                           nadiab_moments(ia,ip,ij,iky,ikx,iz) = moments(ia,ip,ij,iky,ikx,iz,updatetlevel)
                        ENDIF
                     ENDDO
                  ENDDO
               ENDDO
            ENDDO
         ENDDO
      ENDDO

      !! Ensure to kill the moments too high if closue option is set to 1
      IF(CLOS .EQ. 1) THEN
         DO ij=1,local_nj+ngj
            j_int = jarray(ij)
            DO ip=1,local_np+ngp
               p_int = parray(ip)
               DO ia = 1,local_na
                  IF(p_int+2*j_int .GT. dmax) &
                     nadiab_moments(ia,ip,ij,:,:,:) = 0._dp
               ENDDO
            ENDDO
         ENDDO
      ENDIF

      !------------- INTERP AND GRADIENTS ALONG Z ----------------------------------
      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)
                     ! get output
                     DO iz = 1,local_nz
                        ddz_napj(ia,ip,ij,iky,ikx,iz) = f_out(iz)
                     ENDDO
                     ! Parallel numerical diffusion
                     IF (HDz_h) THEN
                        f_in = nadiab_moments(ia,ip,ij,iky,ikx,:)
                     ELSE
                        f_in = moments(ia,ip,ij,iky,ikx,:,updatetlevel)
                     ENDIF
                     CALL  grad_z4(local_nz,ngz,inv_deltaz,f_in,f_out)
                     ! get output
                     DO iz = 1,local_nz
                        ddzND_Napj(ia,ip,ij,iky,ikx,iz) = f_out(iz)
                     ENDDO
                     ! 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
      ! Phi parallel gradient (not implemented fully, should be negligible)
      ! DO ikx = 1,local_nkx
      !   DO iky = 1,local_nky
      !     CALL grad_z(0,phi(iky,ikx,1:local_nz+ngz), ddz_phi(iky,ikx,1:local_nz))
      !   ENDDO
      ! ENDDO

      ! Execution time end
      CALL cpu_time(t1_process)
      tc_process = tc_process + (t1_process - t0_process)
   END SUBROUTINE compute_nadiab_moments_z_gradients_and_interp

   SUBROUTINE compute_Napjz_spectrum
      USE fields, ONLY : moments
      USE array,  ONLY : Napjz
      USE time_integration, ONLY : updatetlevel
      IMPLICIT NONE
      REAL(dp), 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._dp
         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)  + &
                           (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)))
                     ENDDO
                  ENDDO
               ENDDO
            ENDDO
         ENDDO
         ! sum reduction
         buffer     = local_sum
         global_sum = 0._dp
         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(dp) :: 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._dp
                     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(dp) :: 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._dp
                     DO ij = 1, local_nj
                        uperp_ = uperp_ + kernel(ia,ij+ngj/2,iky,ikx,iz+ngz/2,ieven) *&
                           0.5_dp*(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(dp) :: 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._dp
                     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(dp)    :: j_dp
      COMPLEX(dp) :: 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._dp
                     DO ij = 1, local_nj
                        j_dp = jarray(ij+ngj/2)
                        Tperp_ = Tperp_ + kernel(ia,ij+ngj/2,iky,ikx,iz+ngz/2,ieven)*&
                           ((2_dp*j_dp+1)*moments(ia,ip0,ij  +ngj/2,iky,ikx,iz+ngz/2,updatetlevel)&
                                    -j_dp*moments(ia,ip0,ij-1+ngj/2,iky,ikx,iz+ngz/2,updatetlevel)&
                                -(j_dp+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(dp)    :: j_dp
      COMPLEX(dp) :: 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._dp
                     DO ij = 1, local_nj
                        j_dp = REAL(ij-1,dp)
                        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._dp * Tper)/3._dp - dens
   END SUBROUTINE compute_fluid_moments

END MODULE processing