module system_env
use mpi
use omp_lib
#ifdef _OPENACC
use openacc
use cudafor
#endif
implicit none
public
  !> error flag used in MPI calls
integer :: ierror_mpi
save
contains
!> global termination of all MPI processes
subroutine GTC_ABORT
    call MPI_ABORT(MPI_COMM_WORLD,1,ierror_mpi)
end subroutine GTC_ABORT
end module system_env
!=============================================================

!=============================================================
module precision
  use system_env
  integer, parameter :: doubleprec=kind(1.0d0),&
    singleprec=kind(1.0e0),defaultprec=kind(0.0)

! lk stands for Length of real Kind
#ifdef DOUBLE_PRECISION
  integer, parameter :: lk=doubleprec,mpi_Rsize=MPI_DOUBLE_PRECISION,&
                        mpi_Csize=MPI_DOUBLE_COMPLEX
#else
  integer, parameter :: lk=singleprec,mpi_Rsize=MPI_REAL,&
                        mpi_Csize=MPI_COMPLEX
#endif
  real,parameter:: machineEpsilon=10.0_lk*epsilon(1.0_lk)
  save
end module precision
!=============================================================

!=============================================================
module read_in_parameters
  use precision, only: lk
  integer, parameter :: num_modes=8
  integer numerfrc, frcfullf, local_solver_model, nfilter, sol_pfilter, uni_profile, diag_region, sol_para_periodicity, antenna_on, fluid_on, ifullk, kinetice, ifluxtube, izonal
  integer irun, mstep, msnap, ndiag, nonlinear, irestore, toroidaln, track_particles, &
          mpsisol_input, mpsicore_input, mparasol_input, mparacore_input, mtoroidal_input, &
          n_modes(num_modes), m_modes(num_modes), &
          micell, ngyroi, mecell, ngyroe, mfkicell,&
          iflux_core, iflux_sol, global_solver_on
  real(lk) tstep, min_r, gamma0, &
           Zsol_domain0,Zsol_domain1,Rdomain0,Rdomain1, &
           para_diag_location_core, para_diag_location_sol, &
           aion, qion, aelectron, qelectron, &
           afki, qfki, &
           etemp0_input, eden0_input, r0_input, b0_input
!!! constructed temperature/density profile
  integer construct_nT
  real(lk) n_coef(3), t_coef(3), n0_1d, t0_1d
!!! boundary decay control parameters
  integer BC_type, BC_nbound0, BC_nbound1
#ifndef GPU_UM
  !$acc declare create(n_modes)
#endif
  save
end module read_in_parameters
!=============================================================

!=============================================================
module global_parameters
  use precision
  integer,parameter :: gtcout=11, data1d_on=1
  real, parameter :: size_scaling=1.0_lk
! control parameters
  integer  nspecies,istep,mstepall,irk,idiag,nmode,&
           nparami,nparame,nparamfki,mi,mi1,me,me1,mfki,mtoroidal

  real(lk) pi,pi2,pi2_inv,ulength,utime,rho0, betae
  real(lk) torbound
  real(lk) deltaz,zeta1,zeta0
  real(lk) shear_rate,min_b
  real(lk) etemp0,eden0,r0,b0
#ifndef GPU_UM
  !$acc declare create(nparami,nparame)
#endif
! MPI toroidal and particle decomposion
  integer mype,numberpe,npartdom,toroidal_comm,partd_comm,nproc_partd,myrank_partd,&
       nproc_toroidal,myrank_toroidal,left_pe,right_pe,&
       toroidal_domain_location,particle_domain_location,ij_min_core,ij_max_core,ij_min_sol,&
       ij_max_sol,ij_min_tor_core,ij_max_tor_core,ij_min_tor_sol,ij_max_tor_sol,mygrid_core,&
       mygrid_sol,mygrid_tor_core,mygrid_tor_sol

#ifdef _OPENMP
  integer nthreads
#endif

!!XY rolling restart
  integer irest,FileExit
  save
end module global_parameters
!=============================================================

!=============================================================
module petsc_array
  use precision
  integer newcomm,nproc_newcomm,myrank_newcomm
  integer,dimension(:),allocatable :: luserpfperp,lusersfperp

  real(lk),dimension(:),allocatable :: luserafperp,luserafperp0,luserbfperp,luserxfperp
  save
end module petsc_array
!=============================================================

!=============================================================
module particle_array
  use precision
! particle diagnostics: # of quantities per species in history.out and data1d.out
  integer,parameter :: mpdiag=11,mpdata1d=9

! electron
  integer memax, mecore, mesol
  integer, dimension(:),allocatable :: marknume
  integer,dimension(:,:),allocatable :: jtelectron0,jtelectron1,jpelectron
  real(lk),dimension(:),allocatable :: wzelectron,pmarke,zonale,zonalce,markere,nonunie
  real(lk),dimension(:,:),allocatable :: zelectron,zelectron0,zelectron1,&
    rhogyroelectron,rhogyroelectron0,wpelectron,wtelectron0,wtelectron1,densitye,flowe,&
    pressureepara,pressureeperp, densitye0
  real(lk),dimension(mpdiag) :: diagelectron
  real(lk),dimension(:),allocatable :: pfluxe,rdteme
  real(lk),dimension(:,:),allocatable :: data1de
#ifndef GPU_UM
!$acc declare create(marknume,jtelectron0,jtelectron1,jpelectron)
!$acc declare create(wzelectron,zelectron,zelectron0,zelectron1)
!$acc declare create(rhogyroelectron, rhogyroelectron0, wpelectron, wtelectron0)
!$acc declare create(wtelectron1,densitye,densitye0,flowe,pressureeperp,pressureepara,densitye0)
!$acc declare create(diagelectron, rdteme, pfluxe, data1de)
#endif

! themal ion (main ion)
  integer mimax, micore, misol
  integer, dimension(:),allocatable :: marknumi
  integer,dimension(:,:),allocatable :: jtion0,jtion1,jpion
  real(lk),dimension(:),allocatable :: wzion,pmarki,zonali,zonalci,markeri,nonunii
  real(lk),dimension(:,:),allocatable :: zion,zion0,zion1,rhogyroion,rhogyroion0,wpion,wtion0,wtion1,pos,&
    densityi,flowi,pressureipara,pressureiperp, densityi0
!> ion time diagnostic array
!> \n See also: diagnosis.F90, pushi.F90
  real(lk),dimension(mpdiag) :: diagion
  real(lk),dimension(:),allocatable :: pfluxi,rdtemi
  real(lk),dimension(:,:),allocatable :: data1di
#ifndef GPU_UM
!$acc declare create(marknumi, jtion0, jtion1, jpion)
!$acc declare create(wzion, zion, zion0, zion1, rhogyroion, rhogyroion0)
!$acc declare create(wpion, wtion0, wtion1, densityi, densityi0, flowi, pressureipara, pressureiperp)
!$acc declare create(diagion, rdtemi, pfluxi, data1di)
#endif

! fk ion
    integer mfkimax, mfkicore, mfkisol
    integer, dimension(:),allocatable :: marknumfki
    integer,dimension(:,:),allocatable :: jtfki0,jtfki1,jpfki
    real(lk),dimension(:),allocatable :: wzfki,pmarkfki,zonalfki,zonalcfki,markerfki,nonunifki
    real(lk),dimension(:,:),allocatable :: zfki,zfki0,rhogyrofki,rhogyrofki0,wpfki,wtfki0,wtfki1,&
      densityfki,flowfki,pressurefkipara,pressurefkiperp,densityfki0
    real(lk),dimension(mpdiag) :: diagfki
    real(lk),dimension(:),allocatable :: pfluxfki,rdtemfki
    real(lk),dimension(:,:),allocatable :: data1dfki
#ifndef GPU_UM
!$acc declare create(marknumfki, jtfki0, jtfki1, jpfki)
!$acc declare create(wzfki, zfki0, zfki1, zfki)
!$acc declare create(rhogyrofki, rhogyrofki0, wpfki, wtfki0, wtfki1)
!$acc declare create(densityfki, densityfki0, flowfki, pressurefkipara, pressurefkiperp)
!$acc declare create(diagfki, rdtemfki, pfluxfki, data1dfki)
#endif


 save

end module particle_array
!=============================================================

!=============================================================
module gyro_array
  use precision

!> \f$\delta\psi\f$ between each two neigour flux surfaces
  real(lk),dimension(:),allocatable :: deltap

!> gyroaveraging parameters
  real(lk),dimension(:,:),allocatable :: pgyro, zetagyro, tgyro, pgyro2, tgyro2
#ifndef GPU_UM
  !$acc declare create(pgyro, zetagyro)
#endif

end module gyro_array
!=============================================================

