APP下载

NetCDF格式在Windows及Linux平台下的读写

2014-10-21李继祥于立陈龙泉姚仁太郝宏伟范丹吕明华

安徽农业科学 2014年33期

李继祥 于立 陈龙泉 姚仁太 郝宏伟 范丹 吕明华

摘要 使用Linux平台的NetCDF3.6.1源代码程序包,利用hdf提供的Windows平台NetCDF的库,分别编写Windows平台和Linux平台下读写NetCDF的C语言程序及Fortran语言程序。在Windows平台只需要netcdf.dll、libcurl.dll、zlib1.dll和netcdf.lib这4个文件就可以用C和Fortran读写NetCDF格式文件,在Linux平台下只需要libnetcdf.a这1个文件就可以用C和Fortran读写,在不安装NetCDF软件包的情况下就可以使用,并且程序语言均很简单,读写起来很方便,还对比了Windows和Linux平台下C和Fortran的读写精度及速度。该研究对使用NetCDF格式数据的人员有指导和参考价值。

关键词 NetCDF格式;Windows平台;Linux平台;读写速度与精度

中图分类号 P49;S126 文献标识码

A 文章编号 0517-6611(2014)33-11942-04

Read and Write NetCDF Format Files on Windows and Linux Platform

LI Ji-xiang1, YU Li2,3, CHEN Long-quan1 et al (1. Atmospheric Boundary Layer Wind Tunnel Laboratory of China Institute for Radiation Protection, Taiyuan, Shanxi 030006; 2. Taiyuan Satellite Launch Center, Taiyuan, Shanxi 030006; 3. College of Atmospheric Sciences, Lanzhou University, Lanzhou, Gansu 730000)

Abstract Based on the NetCDF3.6.1 source code package on Linux platform, with NetCDF library on Windows platform provided by HDF, we compiled programs to read and write NetCDF files in C language and Fortran language on Windows platform and Linux platform. On Windows platform we only need netcdf. dll, libcurl. dll, zlib1. dll and netcdf.lib to read and write netcdf format files in C and Fortran languages, and we only need libnetcdf.a file to do that on Linux platform, in the case of not installing NetCDF package and the program is very simple, it is convenient to read and write, at last we compared the Windows and Linux platforms read and write speed and accuracy of C and Fortran languages.This paper has certainguidance and reference value on the use of NetCDF format data.

Key words NetCDF format; Windows platform; Linux platform; Read and write speed and accuracy

基金项目 国家自然科学基金项目(11175161)。

作者简介 李继祥(1987- ),男,甘肃秦安人,实习研究员,从事大气边界层和空气污染数值模拟研究。

收稿日期 2014-10-13

NetCDF(Network Common Data Form)是一種网络通用的数据格式,文件最初应用于贮存气象数据,由于其灵活性,能够传输海量的面向阵列(Array-oriented)数据,目前广泛应用于大气科学、水文、海洋学、环境模拟、地球物理等诸多领域。已被国内外许多行业和组织采用,例如NCEP(美国国家环境预报中心)发布的再分析资料及NOAA的CDC(气候数据中心)发布的海洋与大气综合数据集(COADS)均采用NetCDF作为标准。

目前大部分的气象资料均为NetCDF格式,例如广泛使用的中尺度天气预报模式WRF,其输出数据模式即为NetCDF,因此,准确、快速的读写该类型数据是一项有意义的工作。查石祥探讨了在Unix平台下用Fortran读取该类型数据的方法,但未讨论写成NetCDF的方法,而且该方法对系统环境依赖性大[1]。孙建伟等介绍了在Windows下用Fortran读写NetCDF格式的方法,但也需要创建NetCDF环境,读写需要依赖于NetCDF环境[2]。张林等用VC++在Windows下读取了NetCDF格式数据,但除使用dll文件外还需要一些h文件,且读取程序比较麻烦[3]。还有一些作者[4-9]也研究了NetCDF格式读写的方法,但均不系统,很多都依赖于NetCDF环境或借助其他软件读取。为此,笔者介绍只需要NetCDF库之后不再依赖NetCDF环境读写的方法,并且讨论了在Windows和Linux下Fortran和C的读写以及读写的精度和速度,以便更快速更便捷地读写数据。

1 NetCDF数据格式介绍

NetCDF网络通用数据格式是由美国大学大气研究协会(University Corporation for Atmospheric Research,UCAR)的Unidata項目科学家针对科学数据的特点开发的,是一种面向数组型并适于网络共享的数据的描述和编码标准。它具有自描述性、易用性、高可用性、可追加性和平台无关性等特点,所以文件包含自身的描述信息,可以使用多种方式管理和操作这些数据,访问效率高,新数据可沿某一维进行追加,可以由多种软件读取并使用多种语言编写,使用起来灵活方便高效。NetCDF数据的格式是使用者根据需求自己定义的。一个NetCDF数据集包含维(dimensions)、变量(variables)和属性(attributes)3种描述类型。一个NetCDF文件的结构包括以下对象:

NetCDF name{

Dimensions:… //定义维数

Variables:… //定义变量

Attributes:… //属性

Data:…//数据

}

其软件实现形式是一个免费的NetCDF 软件包,内含可访问 NetCDF 数据的工具程序和多种语言的接口函数库,其接口可以在Fortran、C、C++和IDL等多种语言下使用,同时支持多种操作平台下(Linux、Windows等)的读取以及在异构的网络平台间进行数据传输和数据共享。软件包可从其官网http://www.unidata.ucar.edu/software/netcdf/上下载。

2 Windows下的读写

2.1 Windows下用C语言读写

在Windows下对NetCDF格式数据的读写都要依赖于netcdf.dll、libcurl.dll和zlib1.dll这3个dll文件,这3个文件可由NetCDF官网下载或hdf官网下载,同时还需下载netcdf.dll对应的netcdf.lib这个lib文件,而libcurl.dll和zlib1.dll对应的lib不需要。因为libcurl.dll和zlib1.dll是通过netcdf.dll调用其库函数的。

在有了这4个文件后,就可以写C语言程序读写NetCDF格式数据了。在知道NetCDF文件变量名称及维数的以及类型的情况下,以读取整型二维数据为例,程序代码为:

#include

#include

#pragma comment(lib,"netcdf.lib")

#define FILE_NAME "simple_xy.nc"

#define NX 6

#define NY 12

void main()

{

int ncid,varid,x,y,retval;

int data_in[NX][NY];

retval = nc_open(FILE_NAME, NC_NOWRITE, &ncid)

retval = nc_inq_varid(ncid, "data", &varid)

retval = nc_get_var_int(ncid, varid, &data_in[0][0])

/*已读出数据*/

retval = nc_close(ncid)

}

在VS2010下,点击菜单“生成”里的编译,接着点击“生成”里的生成,最后点击“调试”里的开始执行即可(图1)。若要读取其他类型数据,只需按照使用说明找到对应的读取函数即可,具体可参考NetCDF使用说明[10-11]。

图1 Windows下VS2010编译C语言截图

如果不知道NetCDF文件数据的变量名称及维数以及类型的情况,那么这需要读取该信息,可以用以下函数查询(为了避免重复代码,以下均只写出函数名称):

nc_inq_varid

nc_inq_var

nc_inq_dimlen

nc_get_vara_text

nc_inq

nc_inq_dim

用以上函数可以查询出文件里的变量名称、变量类型、维数等信息。这样,就可以读取NetCDF格式数据了。而书写NetCDF格式的数据的程序为(以写整型二维数据为例):

nc_create

nc_def_dim

nc_def_var

nc_enddef

nc_put_var_int

nc_close

这样即可完成Windows下C语言对NetCDF格式数据的读写。

2.2 Windows下用Fortran语言读写

同样,Fortran语言读写要依赖于netcdf.dll、libcurl.dll、zlib1.dll和netcdf.lib这4个文件。但这4个文件是C语言的,Fortran不能直接使用,官网也未公布Windows下Fortran的库,所以使用Fortran读写时要先用C语言做好可供Fortran使用的库或者使用混合编译的方法以实现Fortran对NetCDF的读写。该研究使用VS2010和Intel Fortran读写NetCDF格式数据,所以得先用C语言将上述4个库写成可供Fortran用的库,以读取整型二维数据为例,C程序代码为:

#include

#include

#pragma comment(lib,"netcdf.lib")

typedef int nc_type;

#define size_t unsigned int

int nc_open(const char *path, int mode, int *ncidp);

int nc_inq_varid(int ncid, const char *name, int *varidp);

int nc_get_var_int(int ncid, int varid, int *ip);

int nc_close(int ncid);

void _declspec(dllexport) nf_open(const char *path, int mode, int *ncidp,int *pp)

{

*pp=nc_open(path, mode,ncidp);

}

...

void _declspec(dllexport) nf_close(int ncid,int *pp)

{

*pp=nc_close(ncid);

}

在上述工作的基礎上用VS2010编译成.dll格式,就可以供Fortran使用了。编译具体步骤为:①在新建win32控制台应用程序的应用程序类型中选择dll;②编译生成即可,然后在对应debug或release中可看到lib和dll文件。图2为创建C语言dll库的截图。对应Fortran程序代码为:

module cprog

interface

subroutine nf_open(ll,a,b,c)

!DEC$ ATTRIBUTES C,ALIAS:'_nf_open'::nf_open

character(len=*)::ll

!DEC$ ATTRIBUTES REFERENCE::ll

INTEGER::a

!DEC$ ATTRIBUTES VALUE::a

INTEGER::b

!DEC$ ATTRIBUTES REFERENCE::b

INTEGER::c

!DEC$ ATTRIBUTES REFERENCE::c

end subroutine

...

end interface

end module cprog

program readnc

use cprog

call nf_open

call nf_inq_varid

call nf_get_var_int

call nf_close

end program

将以上生成的lib和dll文件拷贝到Fortran程序目录下,在resoure file中添加lib文件即可,然后就编译、连接、开始执行,这就实现了Fortran在Windows下的读取,当然,书写的程序类似。该程序中的module块是用来连接C生成的库函数的,这是必须要的,如果是Fortran调用Fortran生成的库,则可以不需要。图3为Windows下用Intel Fortran编译Fortran程序的截图。

图2 Windows下VS2010创建C语言dll库截图

图3 Windows下Intel Fortran编译Fortran截图

3 Linux下的读取

在Linux下对NetCDF格式数据的读写只需要依赖于netcdf.a这1个文件即可。在NetCDF官网下载安装包,然后在Linux成功安装NetCDF,在lib文件夹里就可以看到该文件。Linux对NetCDF的读取相比Windows要简单,C和Fortran语言都能读该静态库,以读取整型二维数据为例,程序代码和Windows基本一样,只需要将Windows下的“#pragma comment(lib,"netcdf.lib")”这行删除即可,编译方法为:

gcc -o readnc readnc.c -L. -lnetcdf

./readnc

然后就可以读取了,Fortran的程序代码也和Windows相似,但不需要module块,代码为:

program readnc

implicit none

integer,external::nf_open, nf_inq_varid,nf_get_var_int,nf_get_var_int

integer::istat

istat=nf_open

istat=nf_inq_varid

istat=nf_get_var_int

istat=nf_get_var_int

end program

编译方法和C相似(图4),为:

gfortran -o readnc readnc.f90 -L. -lnetcdf

./readnc

图4 Linux下Fortran代码及编译截图

4 读写速度及精度比较

Windows下用的C编译器是VS 2010,Fortran编译器是Intel Fortran。为了比较运行时间linux系统用的是虚拟机的Red Hat系统,C编译器是gcc,Fortran编译器是pgi fortran和gfortran。读取了一个WRF输出的nc数据并写成文本文件,对其精度进行比较,发现数据差异很小,大部分时候完全一致,只有很小一部分在最后1位(小数点后6位)时数字才可相差1,所以数据读取应该完全正确。运行速度是Windows下的Intel Fortran最快,Windows下的C最慢。在Linux下则是gcc较快而Fortran较慢,Fortran和pgi fortran速度接近。具体运行速度数据见表1。

表1 不同系统下C和Fortran读取数据的时间

5 结语

该研究在Windows下只使用netcdf.dll、libcurl.dll、zlib1.dll和netcdf.lib这4个文件用C和Fortran实现了NetCDF的读写,在Linux下只使用libnetcdf.a一个文件完成了C和Fortran读写,不依赖其他任何NetCDF环境及文件,读写程序简单,使用方便。Linux下的程序相比Windows更加简便一些,并且编译方法也简单方便。在Windows下Intel Fortran的讀写速度比C(VS2010)快4倍多,Linux下C比Fortran快2倍左右。该研究中的程序为读整型二维数据的简单例子,为了更好地读写NetCDF格式,可以参考其使用说明等,希望能起到抛砖引玉的作用。

参考文献

[1]查石祥.NetCDF数据的编程式访问[J].气象科技,2004,32(S1):40-43.

[2] 孙建伟,孙昭晨,陈轩,等.NetCDF格式数据的创建与应用[J].交通标准化,2010(15):31-34.

[3] 张林,高玉春,杨金红,等.基于VC++平台的相控阵天气雷达NetCDF数据读取与产品显示[J].气象科技,2010,38(2):230-234.

[4] 樊军伟.基于GDAL的NetCDF数据提取遥感影像数据信息的研究[D].抚州:东华理工大学,2013.6:23-60.

[5] 白伟华,孙越强,朱光武,等.基于NetCDF的GPS数据预处理[C]//中国空间科学学会空间探测专业委员会第十九次学术会议论文集(下册).中国空间科学学会空间探测专业委员会,2006:660-662.

[6] 贾俊涛,孟婵媛,宋海英,等.基于NetCDF的海底地形网格数据模型创建与调度[J].海洋测绘,2007,2(5):22-25.

[7] 刘文军,李靖,袁昌洪,等.基于NetCDF数据模型的气息资料存储设计[J].安徽农业科学,2009,37(3):1370-1371.

[8] 王想红,刘纪平,徐胜华,等.基于NetCDF数据模型的海洋环境数据三维可视化研究[J].测绘科学,2013,38(2):59-61.

[9] 李永生,刘修伟,杨玉红.气象大数据跨平台分析与应用技术研究[J].电脑知识与技术,2013,9(31):6943-6947.

[10] REW R,DAVIS G,EMMERSON S,et al.The NetCDF Users Guide[Z].2010:1-98.

[11] REW R,DAVIS G,EMMERSON S,et al.NetCDF Users Guide for FORTRAN[Z].1997:1-159.