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 INTEGER, 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