hyper.f90 Source File


Contents

Source Code


Source Code

!> FIXME : Add documentation
!!
!! @note nexp has been changed in a rush.  Only known to be correct for nexp=2
module hyper
  use abstract_config, only: abstract_config_type, CONFIG_MAX_NAME_LEN
  implicit none

  private

  public :: init_hyper, finish_hyper, hyper_diff, D_res, D_v, D_eta, nexp
  public :: read_parameters, wnml_hyper, check_hyper, hypervisc_filter

  public :: hyper_config_type, set_hyper_config, get_hyper_config

  ! D_v, D_eta are hyper coefficients, normalized correctly
  ! i.e., either by unity or by 1/k_perp**2*nexp
  real :: D_v, D_eta, D_hypervisc, D_hyperres, omega_osc, D_hyper
  real :: akx4_max, aky4_max, aky_max, akperp4_max

  integer :: hyper_option_switch, nexp
  integer, parameter :: hyper_option_none = 1, &
       hyper_option_visc = 2, &
       hyper_option_res  = 3, &
       hyper_option_both = 4, &
       hyper_option_simple3D = 5

  character(9) :: hyper_option
  logical :: const_amp, isotropic_shear, damp_zonal_only, gridnorm

  real, dimension (:, :), allocatable :: D_res
  real, dimension (:, :, :), allocatable :: hypervisc_filter

  ! Coefficients for simple3D hyperviscous model
  ! the maximum k_perp ^ 2 including geometric coefficients for non-zonal and zonal modes
  real :: kperp2_max, kperp2_max_zonal
  ! Hyperviscous coefficient, hyperviscous power, ky cut-off, kx cut-off
  real :: D_hyper3D, P_hyper3D, ky_cut, kx_cut
  ! Controls if zonal modes are treated identically to non-zonal modes
  logical :: isotropic_model
  logical :: initialized = .false., hyper_on = .false.

  !> Used to represent the input configuration of hyper
  type, extends(abstract_config_type) :: hyper_config_type
     ! namelist : hyper_knobs
     ! indexed : false
     !> Determines whether hyperviscosity includes time dependent amplitude
     !> factor when calculating damping rate. Recommend `true` for
     !> linear runs and `false` for nolinear runs, since amplutide of
     !> turbulence grows linearly with time in linear run.
     logical :: const_amp = .false.
     !> If `hyper_option = 'both'` is used then this sets both the
     !> hyperresistivity and hyperviscosity damping coefficients. Can
     !> override the individual coefficients with
     !> [[hyper_knobs:D_hyperres]] and [[hyper_knobs:D_hypervisc]].
     real :: d_hyper = -10.0
     !> Used with the simple3D hyperviscosity model of the form
     !> D_hyper3D * (|kperp|/ max |kperp|)^P_hyper3D
     !> and ky_cut, kx_cut set max |kperp|
     real :: d_hyper3d = -10.
     !> Sets hyperresistivity parameter multiplying damping term.
     real :: d_hyperres = -10.0
     !> Sets hyperviscosity parameter multiplying damping term. See
     !> [E. Belli (2006)
     !> thesis](https://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=50BFD54A8F8D72FC225D025FDEDFFFA5?doi=10.1.1.706.9568&rep=rep1&type=pdf)
     !> for more information.
     real :: d_hypervisc = -10.0
     !> If `true` then hyperdissipation only applied to the zonal
     !> mode.
     logical :: damp_zonal_only = .false.
     !> If `true` (default) then set wavenumber parameters entering
     !> the models based on the maximum `ky` and `kx` included in the
     !> current simulation. If `false` then these values are set to 1.
     logical :: gridnorm = .true.
     !> Selects the type of hyper terms included. Should be one of
     !>
     !> - 'default' -- no hyper terms included.
     !> - 'none' -- the same as default.
     !> - 'visc_only' -- only hyperviscosity included.
     !> - 'res_only' -- only hyperresistivity included.
     !> - 'both' -- both viscosity and resistivity included.
     !> - 'simple3D' -- simple hyperviscous dissipation rate of the
     !>    form D_hyper3D * (|kperp|/ max |kperp|)^P_hyper3D
     !>    described in [“Multiscale turbulence in magnetic
     !>    confinement fusion devices”, M. Hardman, DPhil Thesis,
     !>    appendix
     !>    B.4](https://ora.ox.ac.uk/objects/uuid:233a22cb-3c8b-4fe0-a689-4a37d8fe0314)
     !>    note that the dissipation in this version is applied to g, not h, as
     !>    in the reference.
     character(len = 9) :: hyper_option = 'default'
     !> if true damp zonal and drift waves with same dissipation formula
     logical :: isotropic_model = .true.
     !> If `true` then use isotropic shear model.
     logical :: isotropic_shear = .true.
     !> Used with the simple3D hyperviscosity model of the form
     !> D_hyper3D * (|kperp|/ max |kperp|)^P_hyper3D
     !> and ky_cut, kx_cut set max |kperp|
     real :: kx_cut = -10.
     !> Used with the simple3D hyperviscosity model of the form
     !> D_hyper3D * (|kperp|/ max |kperp|)^P_hyper3D
     !> and ky_cut, kx_cut set max |kperp|
     real :: ky_cut = -10.
     !> Sets the power to which \(k_\bot^2\) is raised in the dissipation filter.
     integer :: nexp = 2
     !> Sets a parameter in the anisotropic shearing rate calculation.
     real :: omega_osc = 0.4
     !> Used with the simple3D hyperviscosity model of the form
     !> D_hyper3D * (|kperp|/ max |kperp|)^P_hyper3D
     !> and ky_cut, kx_cut set max |kperp|
     real :: p_hyper3d = 4.
   contains
     procedure, public :: read => read_hyper_config
     procedure, public :: write => write_hyper_config
     procedure, public :: reset => reset_hyper_config
     procedure, public :: broadcast => broadcast_hyper_config
     procedure, public, nopass :: get_default_name => get_default_name_hyper_config
     procedure, public, nopass :: get_default_requires_index => get_default_requires_index_hyper_config
  end type hyper_config_type

  type(hyper_config_type) :: hyper_config

contains

  !> FIXME : Add documentation
  subroutine check_hyper(report_unit)
    implicit none
    integer, intent(in) :: report_unit
    select case (hyper_option_switch)
    case (hyper_option_none)
       if (D_hyperres > 0.) then
          write (report_unit, *)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, fmt="('hyper_option = ',a,' chooses no hyperresistivity.  &
               &D_hyperres ignored.')") trim(hyper_option)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, *)
          D_hyperres = -10.
       end if
       if (D_hypervisc > 0.) then
          write (report_unit, *)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, fmt="('hyper_option = ',a,' chooses no hyperviscosity.  &
               &D_hypervisc ignored.')") trim(hyper_option)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, *)
          D_hypervisc = -10.
       endif

    case (hyper_option_visc)
       hyper_on = .true.
       if (D_hyperres > 0.) then
          write (report_unit, *)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, fmt="('hyper_option = ',a,' chooses no hyperresistivity.  &
               &D_hyperres ignored.')") trim(hyper_option)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, *)
          D_hyperres = -10.
       end if
       if (D_hypervisc < 0.) then
          write (report_unit, *)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, fmt="('hyper_option = ',a,' chooses hyperviscosity but &
               &D_hypervisc < 0.')") trim(hyper_option)
          write (report_unit, fmt="('No hyperviscosity used.')")
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, *)
          hyper_on = .false.
       endif

    case (hyper_option_res)
       hyper_on = .true.
       if (D_hyperres < 0.) then
          write (report_unit, *)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, fmt="('hyper_option = ',a,' chooses hyperresistivity but D_hyperres < 0.')") trim(hyper_option)
          write(report_unit, fmt="('No hyperresistivity used.')")
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, *)
          hyper_on = .false.
       end if
       if (D_hypervisc > 0.) then
          write (report_unit, *)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, fmt="('hyper_option = ',a,' chooses no hyperviscosity.  D_hypervisc ignored.')") trim(hyper_option)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, *)
          D_hypervisc = -10.
       endif

    case (hyper_option_both)
       hyper_on = .true.
       if (D_hyperres < 0.) then
          write (report_unit, *)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, fmt="('hyper_option = ',a,' chooses hyperresistivity but D_hyperres < 0.')") trim(hyper_option)
          write (report_unit, fmt="('No hyperresistivity used.')")
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, *)
       end if
       if (D_hypervisc < 0.) then
          write (report_unit, *)
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, fmt="('hyper_option = ',a,' chooses hyperviscosity but D_hypervisc < 0.')") trim(hyper_option)
          write (report_unit, fmt="('No hyperviscosity used.')")
          write (report_unit, fmt="('################# WARNING #######################')")
          write (report_unit, *)
       endif
       if (D_hypervisc < 0. .and. D_hyperres < 0.) hyper_on = .false.

    end select

    if (hyper_on) then
       write (report_unit, *)
       write (report_unit, fmt="('------------------------------------------------------------')")
       write (report_unit, *)

       select case (hyper_option_switch)

       case (hyper_option_visc)

          write (report_unit, *)
          write (report_unit, fmt="('Hyperviscosity included without hyperresistivity.')")
          if (const_amp) then
             write (report_unit, fmt="('Damping rate is ',e11.4,' at highest k_perp.')") D_hypervisc
          else
             write (report_unit, fmt="('The damping coefficent is ',e11.4)") D_hypervisc
             write (report_unit, fmt="('The damping rate is proportional to the RMS amplitude of the turbulence.')")
          end if
          if (isotropic_shear) then
             write (report_unit, fmt="('The hyperviscosity is isotropic in the perpendicular plane.')")
             write (report_unit, fmt="('This is appropriate for MHD-like calculations.')")
          else
             write (report_unit, fmt="('The hyperviscosity is anisotropic in the perpendicular plane.')")
             write (report_unit, fmt="('This is appropriate for drift-type calculations.')")
             write (report_unit, fmt="('omega_osc = ',e11.4)") omega_osc
          end if

       case (hyper_option_res)

          write (report_unit, *)
          write (report_unit, fmt="('Hyperresistivity included without hyperviscosity.')")
          if (const_amp) then
             write (report_unit, fmt="('Damping rate is ',e11.4,' at highest k_perp.')") D_hyperres
          else
             write (report_unit, fmt="('################# WARNING #######################')")
             write (report_unit, fmt="('const_amp = .false. is not implemented for hyperresistivity.')")
             write (report_unit, fmt="('################# WARNING #######################')")
             write (report_unit, *)
          end if
          if (isotropic_shear) then
             write (report_unit, fmt="('The hyperresistivity is isotropic in the perpendicular plane.')")
             write (report_unit, fmt="('This is appropriate for MHD-like calculations.')")
          else
             write (report_unit, fmt="('################# WARNING #######################')")
             write (report_unit, fmt="('isotropic_shear = .false. is not implemented for hyperresistivity.')")
             write (report_unit, fmt="('################# WARNING #######################')")
             write (report_unit, *)
          end if

       case (hyper_option_both)

          write (report_unit, *)
          write (report_unit, fmt="('Hyperresistivity and hyperviscosity included.')")
          if (const_amp) then
             write (report_unit, fmt="('Damping rate is ',e11.4,' at highest k_perp.')") D_hyperres
          else
             write (report_unit, fmt="('################# WARNING #######################')")
             write (report_unit, fmt="('const_amp = .false. is not implemented for hyperresistivity.')")
             write (report_unit, fmt="('THIS IS AN ERROR.')")
             write (report_unit, fmt="('################# WARNING #######################')")
             write (report_unit, *)
          end if
          if (isotropic_shear) then
             write (report_unit, fmt="('The damping is isotropic in the perpendicular plane.')")
             write (report_unit, fmt="('This is appropriate for MHD-like calculations.')")
          else
             write (report_unit, fmt="('################# WARNING #######################')")
             write (report_unit, fmt="('isotropic_shear = .false. is not implemented for hyperresistivity.')")
             write (report_unit, fmt="('THIS IS AN ERROR.')")
             write (report_unit, fmt="('################# WARNING #######################')")
             write (report_unit, *)
          end if
       end select
    end if
  end subroutine check_hyper

  !> FIXME : Add documentation
  subroutine wnml_hyper(unit)
    implicit none
    integer, intent(in) :: unit
    if (.not. hyper_on) return
    call hyper_config%write(unit)
  end subroutine wnml_hyper

  !> FIXME : Add documentation
  subroutine init_hyper(hyper_config_in)
    use kt_grids, only: ntheta0, naky, akx, aky, kperp2
    use theta_grid, only: gds2, gds21, gds22, shat
    use gs2_time, only: code_dt
    use gs2_layouts, only: init_gs2_layouts
    implicit none
    type(hyper_config_type), intent(in), optional :: hyper_config_in
    integer :: ik, it

    if (initialized) return
    initialized = .true.

    call init_gs2_layouts
    call read_parameters(hyper_config_in)
    call allocate_arrays

    select case (hyper_option_switch)
    case(hyper_option_both, hyper_option_res, hyper_option_visc)
       ! Define variables used in hyperviscosity and hyperresistivity models
       if (gridnorm) then
          akx4_max = akx(ntheta0 / 2 + 1)**(2 * nexp)
          aky_max = aky(naky)
          aky4_max = aky(naky)**(2 * nexp)
          akperp4_max = (akx(ntheta0 / 2 + 1)**2  +  aky(naky)**2)**nexp
       else
          akx4_max = 1.
          aky_max = 1.
          aky4_max = 1.
          akperp4_max = 1.
       end if

       ! Get D_res set up if needed
       if (D_hyperres > 0.) then
          do ik = 1, naky
             do it = 1, ntheta0
                D_res(it, ik) = D_hyperres*code_dt * (aky(ik)**2 + akx(it)**2)**nexp &
                     / akperp4_max
             end do
          end do
          D_eta = D_hyperres / akperp4_max
       end if

       if (D_hypervisc > 0.) D_v = D_hypervisc / akperp4_max

    case(hyper_option_simple3D)
       ! Make the default cut-offs the grid scale
       if (ky_cut <= 0.) ky_cut = aky(naky)
       if (kx_cut <= 0.) kx_cut = akx((ntheta0+1)/2)

       ! Here we're evaluating kperp2 for the specified ky, kx value
       kperp2_max = maxval(ky_cut * ky_cut * gds2 + &
            2.0 * ky_cut * kx_cut * gds21 / shat + &
            kx_cut * kx_cut * gds22 / (shat * shat))

       if (isotropic_model) then
          kperp2_max_zonal = kperp2_max
       else
          kperp2_max_zonal = maxval(kx_cut * kx_cut * gds22 / (shat * shat))
       end if

       ! Calculate the filter
       ik =1  ! Zonal modes
       do it = 1, ntheta0
          hypervisc_filter(:, it, ik) = exp(- ( D_hyper3D * code_dt &
               * ( kperp2(:, it, ik) / kperp2_max_zonal)**(P_hyper3D / 2)))
       end do

       do ik = 2, naky ! Non-zonal modes
          do it = 1, ntheta0
             hypervisc_filter(:, it, ik) = exp(- ( D_hyper3D * code_dt &
                  * ( kperp2(:, it, ik) / kperp2_max )**(P_hyper3D / 2)) )
          end do
       end do
    end select
  end subroutine init_hyper

  !> FIXME : Add documentation
  subroutine read_parameters(hyper_config_in)
    use file_utils, only: error_unit
    use text_options, only: text_option, get_option_value
    use mp, only: proc0
    use warning_helpers, only: not_exactly_equal
    implicit none
    type(hyper_config_type), intent(in), optional :: hyper_config_in
    type (text_option), dimension(6), parameter :: hyperopts = &
         (/ text_option('default', hyper_option_none), &
            text_option('none', hyper_option_none), &
            text_option('visc_only', hyper_option_visc), &
            text_option('res_only', hyper_option_res), &
            text_option('both', hyper_option_both), &
            text_option('simple3D', hyper_option_simple3D) /)
    integer :: ierr

    if (present(hyper_config_in)) hyper_config = hyper_config_in

    call hyper_config%init(name = 'hyper_knobs', requires_index = .false.)

    ! Copy out internal values into module level parameters
    associate(self => hyper_config)
#include "hyper_copy_out_auto_gen.inc"
    end associate

    ierr = error_unit()

    call get_option_value &
         (hyper_option, hyperopts, hyper_option_switch, &
         ierr, "hyper_option in hyper_knobs",.true.)

    if (.not. isotropic_shear .and. nexp /= 2) then
       if (proc0) write (ierr, *) 'Forcing nexp = 2.  Higher values not implemented for anisotropic shear model.'
       nexp = 2
    end if


    select case (hyper_option_switch)
    case (hyper_option_none)
       if (D_hyperres > 0.) then
          if (proc0) write(ierr, *) 'hyper_option = ',hyper_option, &
               ' chooses no hyperresistivity.  D_hyperres ignored.'
          D_hyperres = -10.
       end if
       if (D_hypervisc > 0.) then
          if (proc0) write(ierr, *) 'hyper_option = ',hyper_option, &
               ' chooses no hyperviscosity.  D_hypervisc ignored.'
          D_hypervisc = -10.
       endif

    case (hyper_option_visc)
       hyper_on = .true.
       if (proc0) write (ierr, *) 'WARNING: It is inconsistent to set D_hypervisc different from ', &
            'D_hyperres.  Recommend: Set them equal.'
       if (D_hyperres > 0.) then
          if (proc0) write(ierr, *) 'hyper_option = ',hyper_option, &
               ' chooses no hyperresistivity.  D_hyperres ignored.'
          D_hyperres = -10.
       end if
       if (D_hypervisc < 0.) then
          if (proc0) then
             write(ierr, *) 'hyper_option = ',hyper_option, &
                  ' chooses hyperviscosity but D_hypervisc < 0 is illegal.'
             write(ierr, *) 'No hyperviscosity used.'
          end if
          hyper_on = .false.
       endif

    case (hyper_option_res)
       hyper_on = .true.
       if (proc0) write (ierr, *) 'WARNING: It is inconsistent to set D_hypervisc different from ', &
            'D_hyperres.  Recommend: Set them equal.'
       if (D_hyperres < 0.) then
          if (proc0) then
             write(ierr, *) 'hyper_option = ',hyper_option, &
                  ' chooses hyperresistivity but  D_hyperres < 0 is illegal.'
             write(ierr, *) 'No hyperresistivity used.'
          end if
          hyper_on = .false.
       end if
       if (D_hypervisc > 0.) then
          if (proc0) write(ierr, *) 'hyper_option = ',hyper_option, &
               ' chooses no hyperviscosity.  D_hypervisc ignored.'
          D_hypervisc = -10.
       endif

    case (hyper_option_both)
       hyper_on = .true.

       if (D_hyper < 0.) then
          if (not_exactly_equal(D_hyperres, D_hypervisc)) then
             if (proc0) write (ierr, *) 'WARNING: It is inconsistent to set D_hypervisc different from ', &
                  'D_hyperres.  Recommend: Set them equal.'
          end if
       else
          if (proc0) write (ierr, *) 'WARNING: Setting D_hypervisc = D_hyperres, each to value of D_hyper'
          D_hyperres  = D_hyper
          D_hypervisc = D_hyper
       end if

       if (D_hyperres < 0.) then
          if (proc0) then
             write(ierr, *) 'hyper_option = ',hyper_option, &
                  ' chooses hyperresistivity but  D_hyperres < 0 is illegal.'
             write(ierr, *) 'No hyperresistivity used.'
          end if
       end if
       if (D_hypervisc < 0.) then
          if (proc0) then
             write(ierr, *) 'hyper_option = ',hyper_option, &
                  ' chooses hyperviscosity but D_hypervisc < 0 is illegal.'
             write(ierr, *) 'No hyperviscosity used.'
          end if
       endif
       if (D_hypervisc < 0. .and. D_hyperres < 0.) hyper_on = .false.

    case (hyper_option_simple3D) ! MRH
       hyper_on = .true.

       if (P_hyper3D < 4.) then
          hyper_on = .false.
          if(proc0) write(ierr, *) 'hyper_option = ',hyper_option, &
               ' chooses a simple hyperviscous filter but  P_hyper3D < 4. is illegal.'
          if(proc0) write(ierr, *) 'No hyperviscosity used.'
       endif

       if (D_hyper3D < 0.) then
          hyper_on = .false.
          if(proc0) write(ierr, *) 'hyper_option = ',hyper_option, &
               ' chooses a simple hyperviscous filter but  D_hyper3D < 0 is illegal.'
          if(proc0) write(ierr, *) 'No hyperviscosity used.'
       endif
    end select
  end subroutine read_parameters

  !> FIXME : Add documentation
  subroutine allocate_arrays
    use theta_grid, only: ntgrid
    use kt_grids, only: ntheta0, naky
    implicit none

    if (.not. allocated(D_res)) allocate(D_res(ntheta0, naky))
    if (.not. allocated(hypervisc_filter)) &
         allocate(hypervisc_filter(-ntgrid:ntgrid,ntheta0,naky))

    ! Initialise module level variables
    D_v = 0 ;  D_eta = 0 ; D_res = 0
    akx4_max = 0 ; aky_max = 0 ; aky4_max = 0 ; akperp4_max = 0
    kperp2_max = 0 ; kperp2_max_zonal = 0 ; hypervisc_filter = 1
  end subroutine allocate_arrays

  !> FIXME : Add documentation
  subroutine hyper_diff (g0, phi)
    use gs2_layouts, only: g_lo, ik_idx, it_idx, is_idx
    use theta_grid, only: ntgrid
    use gs2_time, only: code_dt
    use kt_grids, only: aky, akx, naky, ntheta0
    implicit none
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g0
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi
    real, dimension (-ntgrid:ntgrid) :: shear_rate_nz, shear_rate_z, shear_rate_z_nz
    integer :: iglo, ik, it

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! Includes models by Belli and Hammett
! to calculate the x-y avged shearing rate
! S(theta)^2 = <|grad_perp|^4 |phi|^2>
!            =  sum_over_k(kperp^4 * |phi|^2)
!               (times crazy fac factor due to FFT conventions.)
!
! and to implement this anisotropically in k_perp, taking into
! account properties of zonal flows.
!
! Begun December 2001
!
! Number conservation added April 2006
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    if (.not. hyper_on) return

    ! Calculate hypervisc filter for non-simple3D model
    select case (hyper_option_switch)
    case(hyper_option_both, hyper_option_res, hyper_option_visc)
       if (D_hypervisc < 0.) return

       if(isotropic_shear) then
          call iso_shear
       else
          call aniso_shear
       end if
    end select

    ! Apply hypervisc filter
    !$OMP PARALLEL DO DEFAULT(none) &
    !$OMP PRIVATE(iglo, ik, it) &
    !$OMP SHARED(g_lo, damp_zonal_only, g0, hypervisc_filter) &
    !$OMP SCHEDULE(static)
    do iglo = g_lo%llim_proc, g_lo%ulim_alloc
       ik = ik_idx(g_lo, iglo)
       it = it_idx(g_lo, iglo)
       if (damp_zonal_only .and. ik /= 1) cycle
       g0(:, 1, iglo) = g0(:, 1, iglo) * hypervisc_filter(:, it, ik)
       g0(:, 2, iglo) = g0(:, 2, iglo) * hypervisc_filter(:, it, ik)
    end do
    !$OMP END PARALLEL DO
  contains

    !> FIXME : Add documentation
    subroutine aniso_shear
      real, dimension(naky) :: fac
      ! Do the Belli-Hammett anisotropic calculation
      ! which accounts for some zonal/non-zonal differences
      fac = 0.5
      fac(1) = 1.0

      ! shearing rate due to non-zonal modes (on nonzonal modes)
      shear_rate_nz = 0.
      ! shearing rate due to zonal modes (on nonzonal modes)
      shear_rate_z = 0
      ! shearing rate due to nonzonal modes (on zonal modes)
      shear_rate_z_nz = 0.

      ik = 1
      !$OMP PARALLEL DO DEFAULT(none) &
      !$OMP PRIVATE(it) &
      !$OMP SHARED(ik, ntheta0, phi, akx, aky, fac) &
      !$OMP REDUCTION(+: shear_rate_z) &
      !$OMP SCHEDULE(static)
      do it = 1, ntheta0
         shear_rate_z = shear_rate_z + real(conjg(phi(:, it, ik)) &
              * phi(:, it, ik)) * (akx(it)**2 + aky(ik)**2)**2 * fac(ik)
      end do
      !$OMP END PARALLEL DO

      !$OMP PARALLEL DO DEFAULT(none) &
      !$OMP PRIVATE(ik, it) &
      !$OMP SHARED(naky, ntheta0, phi, akx, aky, fac) &
      !$OMP REDUCTION(+: shear_rate_nz, shear_rate_z_nz) &
      !$OMP SCHEDULE(static)
      do ik = 2, naky
         do it = 1, ntheta0
            shear_rate_nz = shear_rate_nz + real(conjg(phi(:, it, ik)) &
                 * phi(:, it, ik)) * (akx(it)**2 + aky(ik)**2)**2 * fac(ik)
            shear_rate_z_nz = shear_rate_z_nz + real(conjg(phi(:, it, ik)) &
                 * phi(:, it, ik)) * aky(ik)**4 * fac(ik)
         end do
      end do
      !$OMP END PARALLEL DO

      ! shear_rate = shear_rate ** 0.5
      shear_rate_nz = 0.5 * ( -omega_osc + sqrt(omega_osc ** 2 + 2 * shear_rate_nz))
      shear_rate_z_nz = 0.5 * ( -omega_osc + sqrt(omega_osc ** 2 + 2 * shear_rate_z_nz))
      shear_rate_z = 0.5 * ( -omega_osc + sqrt(omega_osc ** 2 + 2 * shear_rate_z))
      ! end of anisotropic shearing rate calculations

      ik = 1
      !$OMP PARALLEL DO DEFAULT(none) &
      !$OMP PRIVATE(it) &
      !$OMP SHARED(ik, ntheta0, hypervisc_filter, D_hypervisc, code_dt, akx, &
      !$OMP shear_rate_z_nz, akx4_max) &
      !$OMP SCHEDULE(static)
      do it = 1, ntheta0
         hypervisc_filter(:, it, ik) = exp(- (D_hypervisc * code_dt &
              * (shear_rate_z_nz * akx(it) ** 4 / akx4_max )))
      end do
      !$OMP END PARALLEL DO

      !$OMP PARALLEL DO DEFAULT(none) &
      !$OMP PRIVATE(ik, it) &
      !$OMP SHARED(naky, ntheta0, hypervisc_filter, D_hypervisc, code_dt, akx, aky, &
      !$OMP shear_rate_nz, shear_rate_z, nexp, akperp4_max, akx4_max, aky_max) &
      !$OMP SCHEDULE(static)
      do ik = 2, naky
         do it = 1, ntheta0
            hypervisc_filter(:, it, ik) = exp(- ( D_hypervisc * code_dt &
                 * ( shear_rate_nz *  (aky(ik) ** 2 + akx(it) ** 2 )**nexp / akperp4_max &
                 + shear_rate_z * (akx(it) ** 4) * aky(ik) / (akx4_max * aky_max))))
         end do
      end do
      !$OMP END PARALLEL DO
    end subroutine aniso_shear

    !> FIXME : Add documentation
    subroutine iso_shear
      real, dimension(naky) :: fac
      if (const_amp) then
         shear_rate_nz = 1.
      else
         fac = 0.5
         fac(1) = 1.0
         shear_rate_nz = 0.
         do ik = 1, naky
            if (damp_zonal_only .and. ik > 1) exit
            do it = 1, ntheta0
               shear_rate_nz = shear_rate_nz &
                    + real(conjg(phi(:, it, ik)) * phi(:, it, ik)) &
                    * (akx(it)**2 + aky(ik)**2)**2 * fac(ik)
            end do
         end do
         shear_rate_nz = sqrt(shear_rate_nz)
      end if

      do ik = 1, naky
         !Rely on hypervisc_filter initialised to 1
         if (damp_zonal_only .and. ik > 1) exit
         do it = 1, ntheta0
            hypervisc_filter(:, it, ik) = exp(- ( D_hypervisc * code_dt &
                 * ( shear_rate_nz *  (aky(ik) ** 2 + akx(it) ** 2 )**nexp / akperp4_max)))
         end do
      end do
    end subroutine iso_shear
  end subroutine hyper_diff

  !> FIXME : Add documentation
  subroutine finish_hyper
    implicit none
    hyper_on = .false.
    initialized = .false.
    if (allocated(D_res)) deallocate(D_res)
    if (allocated(hypervisc_filter)) deallocate(hypervisc_filter)
    call hyper_config%reset()
  end subroutine finish_hyper

#include "hyper_auto_gen.inc"
end module hyper