-
Antoine Cyril David Hoffmann authoredAntoine Cyril David Hoffmann authored
cosolver_interface_mod.F90 14.93 KiB
module cosolver_interface
! contains the Hermite-Laguerre collision operators solved using COSOlver.
USE prec_const, ONLY: xp, mpi_xp_c
IMPLICIT NONE
PRIVATE
PUBLIC :: load_COSOlver_mat, compute_cosolver_coll
CONTAINS
!******************************************************************************!
!! compute the collision terms in a (Np x Nj x Nkx x Nky) matrix all at once
!******************************************************************************!
SUBROUTINE compute_cosolver_coll(GK_CO)
USE parallel, ONLY: num_procs_p, comm_p,dsp_p,rcv_p
USE grid, ONLY: &
local_na, &
local_np, ngp, total_np, total_nj, ngj,&
local_nkx, local_nky, local_nz, bar
USE array, ONLY: Capj
USE MPI
USE closure, ONLY: evolve_mom
IMPLICIT NONE
LOGICAL, INTENT(IN) :: GK_CO
COMPLEX(xp), DIMENSION(total_np) :: local_coll, buffer
COMPLEX(xp), DIMENSION(local_np) :: TColl_distr
COMPLEX(xp) :: Tmp_
INTEGER :: iz,ikx,iky,ij,ip,ia,ikx_C,iky_C,iz_C
INTEGER :: ierr
z:DO iz = 1,local_nz
x:DO ikx = 1,local_nkx
y:DO iky = 1,local_nky
a:DO ia = 1,local_na
j:DO ij = 1,total_nj
p:DO ip = 1,total_np
IF(evolve_mom(ip+ngp/2,ij+ngj/2)) THEN !compute for every moments except for closure 1
!! Take GK or DK limit
IF (GK_CO) THEN ! GK operator (k-dependant)
ikx_C = ikx; iky_C = iky; iz_C = iz;
ELSE ! DK operator (only one mat for every k)
ikx_C = 1; iky_C = 1; iz_C = 1;
ENDIF
!! Apply the cosolver collision matrix
CALL apply_cosolver_mat(ia,ip,ij,iky,ikx,iz,ikx_C,iky_C,iz_C,Tmp_)
local_coll(ip) = Tmp_
ELSE
local_coll(ip) = 0._xp
ENDIF
ENDDO p
IF (num_procs_p .GT. 1) THEN
! Reduce the local_sums to root = 0
CALL MPI_REDUCE(local_coll, buffer, total_np, mpi_xp_c, MPI_SUM, 0, comm_p, ierr)
! buffer contains the entire collision term along p, we scatter it between
! the other processes (use of scatterv since Pmax/Np is not an integer)
CALL MPI_SCATTERV(buffer, rcv_p, dsp_p, mpi_xp_c,&
TColl_distr, local_np, mpi_xp_c, &
0, comm_p, ierr)
ELSE
TColl_distr = local_coll
ENDIF
! Write in output variable
DO ip = 1,local_np
Capj(ia,ip,ij,iky,ikx,iz) = TColl_distr(ip)
ENDDO
ENDDO j
ENDDO a
ENDDO y
ENDDO x
ENDDO z
END SUBROUTINE compute_cosolver_coll
!******************************************************************************!
!! compute the collision terms in a (Np x Nj x Nkx x Nky) matrix all at once
!******************************************************************************!
SUBROUTINE apply_cosolver_mat(ia,ip,ij,iky,ikx,iz,ikx_C,iky_C,iz_C,local_coll)
USE grid, ONLY: &
total_na, &
local_np, parray,parray_full, ngp,&
total_nj, jarray,jarray_full, ngj, bar, ngz
USE array, ONLY: nuCself, Cab_F, nadiab_moments
USE species, ONLY: nu_ab
IMPLICIT NONE
INTEGER, INTENT(IN) :: ia,ip,ij,iky,ikx,iz,ikx_C,iky_C,iz_C
COMPLEX(xp), INTENT(OUT) :: local_coll
INTEGER :: ib,iq,il
INTEGER :: p_int,q_int,j_int,l_int
INTEGER :: izi, iqi, ili
izi = iz+ngz/2
p_int = parray_full(ip)
j_int = jarray_full(ij)
!! Apply the cosolver collision matrix
local_coll = 0._xp ! Initialization
q:DO iq = 1,local_np
iqi = iq + ngp/2
q_int = parray(iqi)
l:DO il = 1,total_nj
ili = il + ngj/2
l_int = jarray(ili)
! self interaction + test interaction
local_coll = local_coll + nadiab_moments(ia,iqi,ili,iky,ikx,izi) &
* nuCself(ia,bar(p_int,j_int), bar(q_int,l_int), iky_C, ikx_C, iz_C)
! sum the contribution over the other species
b:DO ib = 1,total_na
IF(ib .NE. ia) THEN
! Field contribution
local_coll = local_coll + nadiab_moments(ib,iqi,ili,iky,ikx,izi) &
* nu_ab(ia,ib) * Cab_F(ia,ib,bar(p_int,j_int), bar(q_int,l_int), iky_C, ikx_C, iz_C)
ENDIF
ENDDO b
ENDDO l
ENDDO q
END SUBROUTINE apply_cosolver_mat
!******************************************************************************!
!!!!!!! Load the collision matrix coefficient table from COSOlver results
!******************************************************************************!
SUBROUTINE load_COSOlver_mat(GK_CO,INTERSPECIES,matfile,collision_kcut) ! Load a sub matrix from iCa files (works for pmax,jmax<=P_full,J_full)
USE basic, ONLY: allocate_array, speak
USE parallel, ONLY: comm_p, my_id
USE grid, ONLY: &
local_na, total_na, &
local_nkx,local_nky, kparray,&
local_nz, ngz, bar,&
pmax, jmax, ieven
USE array, ONLY: Caa, Cab_T, Cab_F, nuCself
USE MPI
USE model, ONLY: Na, LINEARITY
USE species, ONLY: name, nu_ab
USE futils
IMPLICIT NONE
! Input
LOGICAL, INTENT(IN) :: GK_CO, INTERSPECIES
CHARACTER(len=128), INTENT(IN) :: matfile ! COSOlver matrix file names
REAL(xp), INTENT(IN) :: collision_kcut
! Local variables
REAL(xp), DIMENSION(:,:), ALLOCATABLE :: Caa_full,CabT_full, CabF_full ! To load the self entire matrices
REAL(xp), DIMENSION(:,:,:,:), ALLOCATABLE :: Caa__kp ! To store the coeff that will be used along kperp
REAL(xp), DIMENSION(:,:,:,:,:), ALLOCATABLE :: CabF_kp,CabT_kp ! ''
REAL(xp), DIMENSION(:), ALLOCATABLE :: kp_grid_mat ! kperp grid of the matrices
REAL(xp), DIMENSION(2) :: dims
! Indices for row and columns of the COSOlver matrix (4D compressed 2D matrices)
INTEGER :: irow_sub, irow_full, icol_sub, icol_full
INTEGER :: fid ! file indexation
INTEGER :: ip, ij, il, ikx, iky, iz, ik, ikp, ikps_C,ikpe_C,ia,ib ! indices for loops
INTEGER :: pdim, jdim ! dimensions of the COSOlver matrices
INTEGER :: ikp_next, ikp_prev, nkp_mat, ikp_mat
REAL(xp) :: kp_max,kperp_sim, kperp_mat, zerotoone
CHARACTER(len=128) :: var_name, ikp_string, name_a, name_b
CHARACTER(len=1) :: letter_a, letter_b
! Opening the compiled cosolver matrices results
CALL openf(matfile,fid, 'r', 'D', mpicomm=comm_p);
! Get matrices dimensions (polynomials degrees and kperp grid)
CALL getarr(fid, '/dims_i', dims) ! Get the ion polynomial degrees (consider same for electrons)
pdim = dims(1); jdim = dims(2);
!! Here we stop if the matrix is too small, we could put zero to these coefficients otherwise?
IF ( ((pdim .LT. pmax) .OR. (jdim .LT. jmax)) .AND. (my_id .EQ. 0)) ERROR STOP '>> ERROR << P,J Matrix too small'
! Get the dimension kperp grid of the matrices for GK operator
CALL getsize(fid, '/coordkperp', nkp_mat)
CALL allocate_array(kp_grid_mat, 1,nkp_mat)
CALL getarr(fid, '/coordkperp', kp_grid_mat)
kp_max = MAXVAL(kparray)
! check that we have enough kperps mat, if not we apply the kpmax matrix to all k>kpmax
IF (LINEARITY .NE. 'linear') THEN
IF ( (kp_grid_mat(nkp_mat) .LT. 2./3.*kp_max) .AND. (my_id .EQ. 0)) WRITE(*,*) 'warning: Matrix kperp grid too small'
ELSE
IF ( (kp_grid_mat(nkp_mat) .LT. kp_max) .AND. (my_id .EQ. 0)) WRITE(*,*) 'warning: Matrix kperp grid too small !!'
ENDIF
IF (GK_CO) THEN ! GK operator (k-dependant)
ikps_C = 1; ikpe_C = nkp_mat
ELSE ! DK operator, only the k=0 mat applied to all k
ikps_C = 1; ikpe_C = 1
ENDIF
! allocate the temporary matrices
CALL allocate_array( Caa__kp, 1,Na, 1,(pmax+1)*(jmax+1), 1,(pmax+1)*(jmax+1), ikps_C,ikpe_C)
CALL allocate_array( CabF_kp, 1,Na, 1,Na, 1,(pmax+1)*(jmax+1), 1,(pmax+1)*(jmax+1), ikps_C,ikpe_C)
CALL allocate_array( CabT_kp, 1,Na, 1,Na, 1,(pmax+1)*(jmax+1), 1,(pmax+1)*(jmax+1), ikps_C,ikpe_C)
CALL allocate_array( Caa_full,1,(pdim+1)*(jdim+1), 1,(pdim+1)*(jdim+1))
CALL allocate_array( CabT_full,1,(pdim+1)*(jdim+1), 1,(pdim+1)*(jdim+1))
CALL allocate_array( CabF_full,1,(pdim+1)*(jdim+1), 1,(pdim+1)*(jdim+1))
! Loop over every kperp values that will get the collision operator
kp:DO ikp = ikps_C,ikpe_C
! Kperp value in string format to select in cosolver hdf5 file
IF (GK_CO) THEN
write(ikp_string,'(i5.5)') ikp-1
ELSE
write(ikp_string,'(i5.5)') 0
ENDIF
a:DO ia = 1,local_na
name_a = name(ia); letter_a = name_a(1:1)
! get the self colision matrix
! Naming of the array to load (kperp dependant)
! we look for the data stored at e.g. '00001/Caapj/Ceepj'
WRITE(var_name,'(a,a,a,a,a)') TRIM(ADJUSTL(ikp_string)),'/Caapj/C',letter_a,letter_a,'pj'
CALL getarr(fid, var_name, Caa_full) ! get array
! Fill sub array with the usefull polynmial degrees only
DO ip = 0,pmax ! Loop over rows
DO ij = 0,jmax
irow_sub = (jmax +1)*ip + ij +1
irow_full = (jdim +1)*ip + ij +1
DO il = 0,pmax ! Loop over columns
DO ik = 0,jmax
icol_sub = (jmax +1)*il + ik +1
icol_full = (jdim +1)*il + ik +1
Caa__kp (ia,irow_sub,icol_sub,ikp) = Caa_full(irow_full,icol_full)
ENDDO
ENDDO
ENDDO
ENDDO
b: DO ib = 1,local_na
name_b = name(ib); letter_b = name_b(1:1)
IF(INTERSPECIES .AND. (ib .NE. ia)) THEN ! Pitch angle is only applied on like-species
!!!!!!!!!!!!!!! Test and field matrices !!!!!!!!!!!!!!
! we look for the data stored at e.g. '00001/Ceipj/CeipjT'
WRITE(var_name,'(a,a,a,a,a,a,a,a)') TRIM(ADJUSTL(ikp_string)),'/C',letter_a,letter_b,'pj/C',letter_a,letter_b,'pjT'
CALL getarr(fid, var_name, CabT_full)
! we look for the data stored at e.g. '00001/Ceipj/CeipjF'
WRITE(var_name,'(a,a,a,a,a,a,a,a)') TRIM(ADJUSTL(ikp_string)),'/C',letter_a,letter_b,'pj/C',letter_a,letter_b,'pjF'
CALL getarr(fid, var_name, CabF_full)
! Fill sub array with only usefull polynmials degree
DO ip = 0,pmax ! Loop over rows
DO ij = 0,jmax
irow_sub = (jmax +1)*ip + ij +1
irow_full = (jdim +1)*ip + ij +1
DO il = 0,pmax ! Loop over columns
DO ik = 0,jmax
icol_sub = (jmax +1)*il + ik +1
icol_full = (jdim +1)*il + ik +1
CabT_kp(ia,ib,irow_sub,icol_sub,ikp) = CabT_full(irow_full,icol_full)
CabF_kp(ia,ib,irow_sub,icol_sub,ikp) = CabF_full(irow_full,icol_full)
ENDDO
ENDDO
ENDDO
ENDDO
ELSE
CabT_kp(ia,ib,:,:,:) = 0._xp; CabF_kp(ia,ib,:,:,:) = 0._xp
ENDIF
ENDDO b
ENDDO a
ENDDO kp
DEALLOCATE(Caa_full)
DEALLOCATE(CabT_full)
DEALLOCATE(CabF_full)
CALL closef(fid)
IF (GK_CO) THEN ! Interpolation of the kperp matrix values on kx ky grid
IF (my_id .EQ. 0 ) WRITE(*,*) '...Interpolation from matrices kperp to simulation kx,ky...'
DO ikx = 1,local_nkx
DO iky = 1,local_nky
DO iz = 1,local_nz
! Check for nonlinear case if we are in the anti aliased domain or the filtered one
kperp_sim = MIN(kparray(iky,ikx,iz+ngz/2,ieven),collision_kcut) ! current simulation kperp
! Find the interval in kp grid mat where kperp_sim is contained
! Loop over the whole kp mat grid to find the smallest kperp that is
! larger than the current kperp_sim (brute force...)
DO ikp=1,nkp_mat
ikp_mat = ikp ! the first indice of the interval (k0)
kperp_mat = kp_grid_mat(ikp)
IF(kperp_mat .GT. kperp_sim) EXIT ! a matrix with kperq > current kx2 + ky2 has been found
ENDDO
! Interpolation
! interval boundaries
ikp_next = ikp_mat !index of k1 (larger than kperp_sim thanks to previous loop)
ikp_prev = ikp_mat - 1 !index of k0 (smaller neighbour to interpolate inbetween)
if ( (kp_grid_mat(ikp_prev) .GT. kperp_sim) .OR. (kp_grid_mat(ikp_next) .LT. kperp_sim) ) THEN
! write(*,*) 'Warning, linear interp of collision matrix failed!! '
! write(*,*) kp_grid_mat(ikp_prev), '<', kperp_sim, '<', kp_grid_mat(ikp_next)
ENDIF
! 0->1 variable for linear interp, i.e. zero2one = (k-k0)/(k1-k0)
zerotoone = MIN(1._xp,(kperp_sim - kp_grid_mat(ikp_prev))/(kp_grid_mat(ikp_next) - kp_grid_mat(ikp_prev)))
! Linear interpolation between previous and next kperp matrix values
Caa (:,:,:,iky,ikx,iz) = (Caa__kp(:,:,:,ikp_next) - Caa__kp(:,:,:,ikp_prev))*zerotoone + Caa__kp(:,:,:,ikp_prev)
IF(INTERSPECIES) THEN
Cab_T(:,:,:,:,iky,ikx,iz) = (CabT_kp(:,:,:,:,ikp_next) - CabT_kp(:,:,:,:,ikp_prev))*zerotoone + CabT_kp(:,:,:,:,ikp_prev)
Cab_F(:,:,:,:,iky,ikx,iz) = (CabF_kp(:,:,:,:,ikp_next) - CabF_kp(:,:,:,:,ikp_prev))*zerotoone + CabF_kp(:,:,:,:,ikp_prev)
ELSE
Cab_T(:,:,:,:,iky,ikx,iz) = 0._xp
Cab_F(:,:,:,:,iky,ikx,iz) = 0._xp
ENDIF
ENDDO
ENDDO
ENDDO
ELSE ! DK -> No kperp dep, copy simply to final collision matrices
Caa (:,:,:,1,1,1) = Caa__kp(:,:,:,1)
Cab_T(:,:,:,:,1,1,1) = CabT_kp(:,:,:,:,1)
Cab_F(:,:,:,:,1,1,1) = CabF_kp(:,:,:,:,1)
ENDIF
! Deallocate auxiliary variables
DEALLOCATE (Caa__kp); DEALLOCATE (CabT_kp); DEALLOCATE (CabF_kp)
IF( .NOT. INTERSPECIES ) THEN
CALL speak("--Like Species operator--")
Cab_F = 0._xp;
Cab_T = 0._xp;
ENDIF
! Build the self matrix
! nuCself = nuaa*Caa + sum_b_neq_a nu_ab Cab_T
DO ia = 1,total_na
nuCself(ia,:,:,:,:,:) = nu_ab(ia,ia)*Caa(ia,:,:,:,:,:)
DO ib = 1,total_na
IF(ib .NE. ia) THEN
nuCself(ia,:,:,:,:,:) = nuCself(ia,:,:,:,:,:)&
+nu_ab(ia,ib)*Cab_T(ia,ib,:,:,:,:,:)
ENDIF
ENDDO
ENDDO
CALL speak('============DONE===========')
END SUBROUTINE load_COSOlver_mat
!******************************************************************************!
END MODULE cosolver_interface