-
Antoine Cyril David Hoffmann authoredAntoine Cyril David Hoffmann authored
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