TypechoJoeTheme

MetMan's Blog

网站页面

NetCDF错误处理辅助程序

MetMan博 主
2023-10-21
/
0 评论
/
127 阅读
/
508 个字
/
百度已收录
10/21
本文最后更新于 2023年10月21日,已超过 334天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

使用NetCDF API时一定要加上函数返回码检查机制,这会给你节省很多调试时间

因为NetCDF库设计为每一个API函数返回一个整数值用于表明函数执行状态(成功或者失败,失败的原因有多种可能,其错误码也不同),但程序不会因为函数执行未成功便终止程序,而是会继续执行下去,但通过API函数获取的信息是错误的。

下面以读一个NetCDF文件获取其维数信息为例说明。有一个文件名为tos_O1_2001-2002.nc文件,元数据如下:

dimensions:
        lon = 180 ;
        lat = 170 ;
        time = UNLIMITED ; // (24 currently)
        bnds = 2 ;
variables:
        double lon(lon) ;
                lon:standard_name = "longitude" ;
...

假如不小心敲错了文件名,如以下代码所示,同时调用netcdf api也没有检查函数返回值,你会发现程序会正常运行结束,输出lon/lat维数大小,但结果是不对的。

program main
  use netcdf
  implicit none
  integer :: ncid,status
  integer :: nlon,nlat
  integer :: londimid,latdimid
  character(len=128) :: file

  file = 'tos_O1_2001-2002.nc1'   !wrong filename
  status = nf90_open(trim(file),NF90_NOWRITE,ncid)
  status = nf90_inq_dimid(ncid, "lon", londimid)
  status = nf90_inquire_dimension(ncid,londimid, len=nlon)
  status = nf90_inq_dimid(ncid, "lat", latdimid)
  status = nf90_inquire_dimension(ncid,latdimid, len=nlat)
  print*, 'nlon = ',nlon, 'nlat = ',nlat

  status = nf90_close(ncid)
end

我这里测试结果如下,坐标维大小完全不对。

$ ifort -I$NETCDF/include test.f90 -L$NETCDF/lib -lnetcdff -lnetcdf
$ ./a.out
 nlon =            4 nlat =            4

但如果加上对NetCDF函数返回码检查机制,则可以在发现错误时输出错误原因并提前退出程序,官方建议handle_error处理机制:判断返回码是否等于NF90_NOERR,不等于说明出错,利用NF90_STRERROR函数将整数返回码转换成字符串,更加有意义,最后终止程序。

subroutine handle_err(status)
  use netcdf
  implicit none
  integer :: status
  if(status /= nf90_noerr) then
    print*, nf90_strerror(status)
    STOP 'Stopped'
  endif
end subroutine handle_err

program main
  use netcdf
  implicit none
  integer :: ncid,status
  integer :: nlon,nlat
  integer :: londimid,latdimid
  character(len=128) :: file

  file = 'tos_O1_2001-2002.nc1'
  status = nf90_open(trim(file),NF90_NOWRITE,ncid)
  call handle_err(status)

  status = nf90_inq_dimid(ncid, "lon", londimid)
  call handle_err(status)

  status = nf90_inquire_dimension(ncid,londimid, len=nlon)
  call handle_err(status)

  status = nf90_inq_dimid(ncid, "lat", latdimid)
  call handle_err(status)

  status = nf90_inquire_dimension(ncid,latdimid, len=nlat)
  call handle_err(status)

  print*, 'nlon = ',nlon, 'nlat = ',nlat

  status = nf90_close(ncid)
end

编译执行结果如下,报告没有找到文件,并终止程序。

 No such file or directory

Stopped

如果遇到坐标名不对,会报NetCDF: Invalid dimension ID or name等等信息,有助于排查。

handle_err子程序

官方文档里使用的handle_err函数如下(Fortran 90/77接口的):

  • Fortran 90接口
subroutine handle_err(status)
  use netcdf
  implicit none
  integer :: status
  if(status /= nf90_noerr) then
    print*, nf90_strerror(status)
    STOP 'Stopped'
  endif
end subroutine handle_err
  • Fortran 77 接口
SUBROUTINE HANDLE_ERR(STATUS)
INCLUDE 'netcdf.inc'
INTEGER STATUS
IF (STATUS .NE. NF_NOERR) THEN
  PRINT *, NF_STRERROR(STATUS)
  STOP 'Stopped'
ENDIF
END

加强版错误处理子程序

参考ARWPOST使用的错误处理子程序,其利用C标准的预定义宏(__FILE__ , __LINE__)变量获得出错源代码文件及行数。

子程序定义:

  subroutine handle_nc_error(src_file,lineno,status)
    use netcdf 
    implicit none
    character(len=*),intent(in) :: src_file
    integer,intent(in) :: lineno,status

    if(status/=nf90_noerr)then
      print*, src_file, '(', lineno, '): ',trim(nf90_strerror(status))
      write(0,*) src_file, '(', lineno, '): ',trim(nf90_strerror(status))
      stop "Stopped by netCDF"
    endif
  end subroutine handle_nc_error

子程序调用:

call handle_nc_error(__FILE__, __LINE__, status)

既然它们是宏定义,源代码就必须经过预处理,否则直接编译会出错,使用-cpp进行预处理。

$ ifort -cpp -I$NETCDF/include test.f90 -L$NETCDF/lib -lnetcdff -lnetcdf

执行输出

$ ./a.out
 test.f90(          35 ): No such file or directory
 test.f90(          35 ): No such file or directory
Stopped by netCDF

小结

使用NetCDF API时一定要加上函数返回码检查机制,这会给你节省很多调试时间

朗读
赞(0)
赞赏
感谢您的支持,我会继续努力哒!
版权属于:

MetMan's Blog

本文链接:

https://blog.metman.top/index.php/archives/24/(转载时请注明本文出处及文章链接)

评论 (0)

互动读者

标签云

最新回复

暂无回复

登录
X
用户名
密码