ESMF_IOFileTypeCheck.F90 Source File


Source Code

! $Id$
!
! Earth System Modeling Framework
! Copyright (c) 2002-2023, University Corporation for Atmospheric Research,
! Massachusetts Institute of Technology, Geophysical Fluid Dynamics
! Laboratory, University of Michigan, National Centers for Environmental
! Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
! NASA Goddard Space Flight Center.
! Licensed under the University of Illinois-NCSA License.
!
!==============================================================================
!
#define ESMF_FILENAME "ESMF_IOFileTypeCheck.F90"
!
!     ESMF IOFileTypeCheck Module
      module ESMF_IOFileTypeCheckMod
!
!------------------------------------------------------------------------------
! INCLUDES
#include "ESMF.h"
!==============================================================================
!BOPI
! !MODULE: ESMF_IOFileTypeCheckMod - Grid I/O utility class
!
! !DESCRIPTION:
!
! The code in this file check the grid file type based on the contents in the file
! files
!
!------------------------------------------------------------------------------
! !USES:
      use ESMF_UtilTypesMod
      use ESMF_UtilMod
      use ESMF_InitMacrosMod    ! ESMF initializer macros
      use ESMF_LogErrMod        ! ESMF error handling
      use ESMF_VMMod
      use ESMF_IOUGridMod
      use ESMF_IOGridspecMod
      use ESMF_IOScripMod
#ifdef ESMF_NETCDF
      use netcdf
#endif

!     NEED TO ADD MORE HERE
      implicit none
!------------------------------------------------------------------------------
!
! !PUBLIC MEMBER FUNCTIONS:
!
! - ESMF-public methods:
  public ESMF_FileTypeCheck

!==============================================================================

      contains

!==============================================================================

! -------------------------- ESMF-public method -------------------------------
! Return the file type of a given grid file:
! It could be one of the following:
!   ESMF_FILEFORMAT_SCRIP,  ESMF_FILEFORMAT_UGRID,
!   ESMF_FILEFORMAT_ESMFMESH,
!   ESMF_FILEFORMAT_CFGRID (same as ESMF_FILEFORMAT_GRIDSPEC), and
!   ESMF_FILEFORMAT_MOSAIC (GRIDSPEC Mosaic file) and ESMF_FILEFORMAT_TILE (GRIDSPEC Tile file)
!
!   The rule to check the file format is as follows:
!   ESMF_FILEFORMAT_UGRID: a variable with attribute "cf_role" or "standard_name" set to "mesh_topology"
!   ESMF_FILEFORMAT_MOSAIC: a variable with attribute "standard_name" set to "grid_mosaic_spec"
!   ESMF_FILEFORMAT_TILE:  a variable with attribute "standard_name" set to "grid_tile_spec"
!   ESMF_FILEFORMAT_ESMFMESH: variables nodeCoords and elementConn exist
!   ESMF_FILEFORMAT_SCRIP:  variables grid_corner_lon and grid_corner_lat exist
!   ESMF_FILEFORMAT_CFGRID: variables with attributes "degree_north" and "degree_east" (or similar) exist, and other formats aren't matched
! -----------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_FileTypeCheck"
  subroutine ESMF_FileTypeCheck(filename, filetype, varname, rc)

! ARGUMENTS:
    character(len=*),  intent(in)           :: filename
    type(ESMF_Fileformat_Flag), intent(out) :: filetype
    character(len=*), intent(out), optional :: varname  ! for UGRID/GRIDSPEC files
    integer, intent(out), optional          :: rc

    logical :: foundlon, foundlat
    logical :: foundscriplon, foundscriplat
    logical :: foundesmfcoord, foundesmfconn
    logical :: useStandname, foundtype
    integer :: ncStatus
    integer ::  gridid, varid, dimid, len
    character(len=128) :: attvalue
    integer :: i, nvars
    character(len=128) :: errmsg
    integer, parameter :: nf90_noerror = 0

    if (present(rc)) rc = ESMF_FAILURE
    filetype = ESMF_FILEFORMAT_UNKNOWN

    foundlon = .false.
    foundlat = .false.
    foundscriplon = .false.
    foundscriplat = .false.
    foundesmfcoord = .false.
    foundesmfconn = .false.
    foundtype = .false.

#ifdef ESMF_NETCDF
    ncStatus = nf90_open (path=filename, mode=nf90_nowrite, ncid=gridid)
    errmsg = 'Fail to open '//trim(filename)
    if (CDFCheckError (ncStatus, &
            ESMF_METHOD, &
            ESMF_SRCLINE,&
            errmsg, &
            rc)) return

     !find out how many variables are in the file
     ncStatus = nf90_inquire(gridid, nVariables=nvars)
     errmsg = 'nf90_inquire failed '//trim(filename)
     if (CDFCheckError (ncStatus, &
               ESMF_METHOD, &
               ESMF_SRCLINE,&
               errmsg, &
               rc)) return
     do i=1,nvars
        ! Check UGRID or GRIDSPEC MOSAIC/TILE
        ! Seach for a variable with cf_role or standard_name = 'mesh_topology'
        ncStatus=nf90_get_att(gridid, i, 'cf_role', attvalue)
        if (ncStatus == nf90_noerror) then
          ncStatus = nf90_inquire_attribute(gridid, i, 'cf_role', len=len)
        else
          ncStatus = nf90_get_att (gridid, i, "standard_name", attvalue)
          useStandName = .true.
          if (ncStatus == nf90_noerror) then
             ncStatus = nf90_inquire_attribute(gridid, i, 'standard_name', len=len)
          endif
        endif
        if ((ncStatus == nf90_noerror) .and. (len .ge. 1)) then
          if (attvalue(len:len) .eq. achar(0)) len = len-1
          if (attvalue(1:len) .eq. 'mesh_topology') then
             fileType=ESMF_FILEFORMAT_UGRID
             foundtype = .true.
          elseif (useStandName .and. attvalue(1:len) .eq. 'grid_mosaic_spec') then
             ! It is a GRIDSPEC MOSAIC file
             filetype = ESMF_FILEFORMAT_MOSAIC
             foundtype = .true.
          elseif (useStandName .and. attvalue(1:len) .eq. 'grid_tile_spec') then
             ! It is a GRIDSPEC TILE file
             filetype = ESMF_FILEFORMAT_TILE
             foundtype = .true.
          endif
          if (foundtype) then
            if (present(varname)) then
              ncStatus = nf90_inquire_variable(gridid, i, name=attvalue)
              errmsg = 'nf90_inquire_variable failed '//trim(filename)
              if (CDFCheckError (ncStatus, &
                   ESMF_METHOD, &
                   ESMF_SRCLINE,&
                   errmsg, &
                   rc)) return
              varname = trim(attvalue)
            endif
            rc=ESMF_SUCCESS
            goto 1000
          endif
        endif
        ! check if it is CFGRID
        ! check if the coordinate variables exist or not
        ncStatus = nf90_inquire_attribute(gridid, i, "units", len=len)
        if ((ncStatus == nf90_noerror) .and. (len .ge. 1)) then
          ncStatus=nf90_get_att(gridid, i, 'units', attvalue)
          if (ncStatus /= nf90_noerror) then
            print '("NetCDF error: ", A)', trim(nf90_strerror(ncStatus))
            goto 1000
          endif
          if (attvalue(len:len) .eq. achar(0)) len = len-1
          if (len >= 6 .and. (attvalue(1:6) .eq. "degree")) then
            if (attvalue(1:len) .eq. "degrees_east" .or. &
                attvalue(1:len) .eq. "degree_east" .or. &
                attvalue(1:len) .eq. "degree_E" .or. &
                attvalue(1:len) .eq. "degrees_E" .or. &
                attvalue(1:len) .eq. "degreeE" .or. &
                attvalue(1:len) .eq. "degreesE")  then
                foundlon = .true.
             else if (attvalue(1:len) .eq. "degrees_north" .or. &
                attvalue(1:len) .eq. "degree_north" .or. &
                attvalue(1:len) .eq. "degree_N" .or. &
                attvalue(1:len) .eq. "degrees_N" .or. &
                attvalue(1:len) .eq. "degreeN" .or. &
                attvalue(1:len) .eq. "degreesN")  then
                foundlat = .true.
             endif
          endif
        endif

        ! Check the variable names to determine if it is SCRIP or ESMFMESH
        ncStatus = nf90_inquire_variable(gridid, i, name=attvalue)
        errmsg = 'nf90_inquire_variable failed '//trim(filename)
        if (CDFCheckError (ncStatus, &
                ESMF_METHOD, &
                ESMF_SRCLINE,&
                errmsg, &
                rc)) return
        if (trim(attvalue) .eq. 'grid_corner_lon') then
           foundscriplon = .true.
        elseif (trim(attvalue) .eq. 'grid_corner_lat') then
           foundscriplat = .true.
        elseif (trim(attvalue) .eq. 'nodeCoords') then
           foundesmfcoord = .true.
        elseif (trim(attvalue) .eq. 'elementConn') then
           foundesmfconn = .true.
        endif
     enddo

     if (foundesmfcoord .and. foundesmfconn) then
        filetype = ESMF_FILEFORMAT_ESMFMESH
        rc=ESMF_SUCCESS
        goto 1000
     endif

     if (foundscriplon .and. foundscriplat) then
         filetype = ESMF_FILEFORMAT_SCRIP
         rc=ESMF_SUCCESS
         goto 1000
     endif

     if (foundlon .and. foundlat) then
        filetype = ESMF_FILEFORMAT_CFGRID
        rc=ESMF_SUCCESS
        goto 1000
     endif

1000 continue
     ncStatus = nf90_close(gridid)
     if (CDFCheckError (ncStatus, &
        ESMF_METHOD,  &
        ESMF_SRCLINE, errmsg, &
        rc)) return

     return
#else
    call ESMF_LogSetError(ESMF_RC_LIB_NOT_PRESENT, &
                 msg="- ESMF_NETCDF not defined when lib was compiled", &
                 ESMF_CONTEXT, rcToReturn=rc)
    return
#endif

  end subroutine ESMF_FileTypeCheck

#undef  ESMF_METHOD
#define ESMF_METHOD "CDFCheckError"
function CDFCheckError (ncStatus, module, fileName, lineNo, errmsg, rc)

    logical                       :: CDFCheckError

    integer,          intent(in)  :: ncStatus
    character(len=*), intent(in)  :: module
    character(len=*), intent(in)  :: fileName
    integer,          intent(in)  :: lineNo
    character(len=*), intent(in)  :: errmsg
    integer, intent(out),optional :: rc

    integer, parameter :: nf90_noerror = 0

    CDFCheckError = .FALSE.

#ifdef ESMF_NETCDF
    if ( ncStatus .ne. nf90_noerror) then
        call ESMF_LogWrite (  &
            msg="netCDF Error: " // trim (errmsg) // ": " // trim (nf90_strerror(ncStatus)),  &
            logmsgFlag=ESMF_LOGMSG_ERROR, &
            line=lineNo, file=fileName, method=module)
        print '("NetCDF Error: ", A, " : ", A)', &
            trim(errmsg),trim(nf90_strerror(ncStatus))
        call ESMF_LogFlush()
        if (present(rc)) rc = ESMF_FAILURE
        CDFCheckError = .TRUE.
    else
       if (present(rc)) rc = ESMF_SUCCESS
       return
    end if
#else
    call ESMF_LogSetError(rcToCheck=ESMF_RC_LIB_NOT_PRESENT, &
                 msg="- ESMF_NETCDF not defined when lib was compiled", &
                 ESMF_CONTEXT, rcToReturn=rc)
    return
#endif

end function CDFCheckError


end module ESMF_IOFileTypeCheckMod