! This file is part of GTC version 4.4 
! GTC version 4.4 is released under the 3-Clause BSD license:

! Copyright (c) 2002,2010,2016, GTC Team (team leader: Zhihong Lin, zhihongl@uci.edu)
! All rights reserved.

! Redistribution and use in source and binary forms, with or without 
! modification, are permitted provided that the following conditions are met:

! 1. Redistributions of source code must retain the above copyright notice, 
!    this list of conditions and the following disclaimer.

! 2. Redistributions in binary form must reproduce the above copyright notice, 
!    this list of conditions and the following disclaimer in the documentation 
!    and/or other materials provided with the distribution.

! 3. Neither the name of the GTC Team nor the names of its contributors may be 
!    used to endorse or promote products derived from this software without 
!    specific prior written permission.
! ==============================================================================

!> Common utility functions and subroutines

module utility
  use system_env, only: GTC_ABORT
  implicit none
  private
  public std_err, check_allocation, mstat

  ! messages are assumed shorter than 200 characters
  integer, parameter :: MAX_MESSAGE_LENGTH = 200

  ! temporary status holder
  integer:: mstat

  contains

    ! write message to standard error
    ! Standard: Fortran 2003
    subroutine std_err(message)

      use ISO_FORTRAN_ENV , only: ERROR_UNIT ! access computing environment
      character(len = *), intent(in) :: message

      write(ERROR_UNIT,*)  message
    end subroutine std_err

    subroutine check_allocation(stat, tag)
      use global_parameters, only: mype, gtcout

      ! stat returned from an "allocate" statement
      integer, intent(in):: stat
      ! stat converted to string
      character(len = 5) :: stat_str
      character(len = 16) :: mype_str
      ! a specifier that helps identify the allocation failure location
      character(len = *), intent(in):: tag
      character(len = MAX_MESSAGE_LENGTH) :: message

      if(stat /= 0) then
        write(stat_str, "(I1)") stat
        write(mype_str, "(I12)") mype
        message = "ALLOCATION ERROR: "//trim(stat_str)//" ,  Location tag: "//trim(tag)&
          //" , PE# "//trim(mype_str)
        call std_err(message)
        call GTC_ABORT
      endif
    end subroutine check_allocation

end module utility

!> \brief NetCDF wrapper functions
module netcdf_wrapper
  use netcdf
  use system_env, only: GTC_ABORT, MPI_COMM_WORLD
  implicit none
  public

#ifdef DOUBLE_PRECISION
  integer,parameter:: NC_REAL=NF90_DOUBLE
#else
  integer,parameter:: NC_REAL=NF90_FLOAT
#endif
  integer ierror

  contains
    !> check if NF90 calls have no error
    subroutine check_nf(status)
      integer, intent(in):: status

      if (status /= NF90_NOERR) then
        print *, trim(NF90_STRERROR(status))
        call GTC_ABORT
      endif
    end subroutine check_nf

end module netcdf_wrapper
