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