NETCDF入門

轉載自:http://www.cnblogs.com/davidgu/p/3572317.htmlhtml

 

1、概述
  NetCDF全稱爲network Common Data Format,中文譯法爲「網絡通用數據格式」,
對程序員來講,它和zip、jpeg、bmp文件格式相似,都是一種文件格式的標準。netcdf
文件開始的目的是用於存儲氣象科學中的數據,如今已經成爲許多數據採集軟件的生成文件
的格式。
   從數學上來講,netcdf存儲的數據就是一個多自變量的單值函數。用公式來講就是
f(x,y,z,...)=value, 函數的自變量x,y,z等在netcdf中叫作維(dimension)
或座標軸(axix),函數值value在netcdf中叫作變量(Variables).而自變量和函數值
在物理學上的一些性質,好比計量單位(量綱)、物理學名稱等等
在netcdf中就叫屬性(Attributes).git

2、netcdf的下載
 netcdf的是官方網站爲http://www.unidata.ucar.edu/software/netcdf/
 在本文中,咱們主要討論在windows平臺上使用netcdf軟件庫。咱們將要從這個網站上
下載以下資源
⑴netcdf的源代碼,目前的地址爲
 ftp://ftp.unidata.ucar.edu/pub/netcdf/netcdf-4/netcdf-beta.tar.gz
⑵netcdf的在windows平臺預編譯好的dll,地址爲
 ftp://ftp.unidata.ucar.edu/pub/netcdf/contrib/win32/netcdf-3.6.1-win32.zip
 解壓后里面有以下東西
 netcdf.dll  爲編譯好的dll
 ncgen.exe  爲生成netcdf文件的工具
 ncdump.exe 爲讀取netcdf文件的工具
 netcdf.lib 和 netcdf.exp在編程時會用到,後面會講。
⑶netcdf的相關文檔,包括
 ①netcdf的用戶手冊,下載地址爲http://www.unidata.ucar.edu/software/netcdf/docs/netcdf.pdf 
 ②netcdf的入門教程, 下載地址爲http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial.pdf
 ③netcdf的c接口api手冊,下載地址爲http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c.pdf
 下面咱們來看netcdf文件的具體內容。程序員

3、netcdf文件的內容
一個netcdf文件的結構包括如下對象:
一、變量(Variables)
   變量對應着真實的物理數據。好比咱們家裏的電錶,每一個時刻顯示的讀數表示用戶的到該時刻的耗電量。
這個讀數值就能夠用netcdf裏的變量來表示。它是一個以時間爲自變量(或者說自變量個數爲一維)的單值
函數。再好比在氣象學中要做出一個氣壓圖,就是「東經xx度,北緯yy度的點的大氣壓值爲多少帕」,這是
一個二維單值函數,兩維分別是經度和緯度。函數值爲大氣壓。
   從上面的例子能夠看出,netcdf中的變量就是一個N維數組,數組的維數就是實際問題中的自變量個數,
數組的值就是觀測獲得的物理值。變量(數組值)在netcdf中的存儲類型有六種,ascii字符(char) ,字節(byte), 短整型(short), 整型(int), 浮點(float), 雙精度(double). 顯然這些類型和c中的類型一致,搞C的朋友應該很快就能明白。
二、維(dimension)
   一個維對應着函數中的某個自變量,或者說函數圖象中的一個座標軸,在線性代數中就是一個N維向量
的一個份量(這也是維這個名稱的由來)。在netcdf中,一個維具備一個名字和範圍(或者說長度,也就
是數學上所說的定義域,能夠是離散的點集合或者連續的區間)。在netcdf中,維的長度基本都是有限的,
最多隻能有一個具備無限長度的維。
三、屬性(Attribute)
   屬性對變量值和維的具體物理含義的註釋或者說解釋。由於變量和維在netcdf中都只是無量綱的數字,
要想讓人們明白這些數字的具體含義,就得靠屬性這個對象了。
   在netcdf中,屬性由一個屬性名和一個屬性值(通常爲字符串)組成。好比,在某個cdl文件
(cdl文件的具體格式在下一節中講述)中有這樣的代碼段
   temperature:units = "celsius" ;    
   前面的temperature是一個已經定義好的變量(Variable),即溫度,冒號後面的units就是屬性名,
表示物理單位,=後面的就是units這個屬性的值,爲「celsius」 ,即攝氏度,整個一行代碼的意思就是
溫度這個物理量的單位爲celsius,很好理解。編程

3、CDL結構
   CDL全稱爲network Common data form Description Language,它是用來描述netcdf文件
的結構的一種語法格式。它包括前面所說的三種netcdf對象(變量、維、屬性)的具體定義。
看一個具體例子(這個例子cdl文件是從netcdf教程中的2.1 節The simple xy Example摘出來的) 
netcdf simple_xy {
dimensions:
x = 6 ;
y = 12 ;
variables:
int data(x, y) ;
data:
data =
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71 ;
}
上面的代碼定義了一個符合netcdf格式的結構simple_xy,  
這個結構包括三個部分
一、維的定義,以dimensions:關鍵字開頭
   dimensions:
 x = 6 ;
 y = 12 ;
 定義了兩個軸(或者說兩維),名字分別爲x和y,x軸的長度(準確的說是座標點的個數)爲6,
 y軸的長度爲12。
二、變量的定義:以variables:開頭
 variables:
  int data(x, y);
  定義了一個以x軸和y軸爲自變量的函數data,數學公式就是f(x,y)=data;
  注意維出現的順序是有序的,它決定data段中的具體賦值結果.
三、數據的定義,以data:開頭
 data:
data =
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71 ;
這個段數據用數學的函數公式f(x,y)=data來看,
就是  x=0,y=0時,data = 0;
     x=0,y=1時,data = 1;
     
     
     x=5,y=11是,data=71;
要注意的是,
一、賦值順序:
咱們給出的是c格式的cdl文件,所以這裏的賦值順序和c語言中的一致,也就是一般所說的「行式賦值」,
而fortran語言中則是「列式賦值」,所以在fortran格式的cdl文件中,data段的數值順序和這裏正好
行列互換。     
二、自變量的默認取值和座標變量
   若是隻給出維的長度,那麼維的值默認從0開始,而後自動加1,到(長度-1)中止,
   不少狀況下咱們要本身給出每一個點的座標值,這時就須要用到netcdf裏的座標變量
   "coordinate varibles":增長一個和只和維相關的一元函數(自變量)並給出它的取值範圍。
   好比下面的cdl文件(摘自netcdf教程中的2.2 The sfc pres temp Example)
   netcdf sfc_pres_temp {
 dimensions:
 latitude = 6 ;        //緯度軸
 longitude = 12 ;      //經度軸
 variables:
 float latitude(latitude) ;    //座標變量,存儲具體緯度
 latitude:units = "degrees_north" ;
 float longitude(longitude) ;  //座標變量,存儲具體緯度
 longitude:units = "degrees_east" ;
 float pressure(latitude, longitude) ;   //某個點(經度和緯度的交點)的大氣壓值
 pressure:units = "hPa" ;           //大氣壓的單位爲
 float temperature(latitude, longitude) ; //某個點(經度和緯度的交點)的溫度值
 temperature:units = "celsius" ;    //溫度的單位爲
 data:
 latitude = 25, 30, 35, 40, 45, 50 ;
 longitude = -125, -120, -115, -110, -105, -100, -95, -90, -85, -80, -75, -70 ;
 pressure =
 900, 906, 912, 918, 924, 930, 936, 942, 948, 954, 960, 966,
 901, 907, 913, 919, 925, 931, 937, 943, 949, 955, 961, 967,
 902, 908, 914, 920, 926, 932, 938, 944, 950, 956, 962, 968,
 903, 909, 915, 921, 927, 933, 939, 945, 951, 957, 963, 969,
 904, 910, 916, 922, 928, 934, 940, 946, 952, 958, 964, 970,
 905, 911, 917, 923, 929, 935, 941, 947, 953, 959, 965, 971 ;
 temperature =
 9, 10.5, 12, 13.5, 15, 16.5, 18, 19.5, 21, 22.5, 24, 25.5,
 9.25, 10.75, 12.25, 13.75, 15.25, 16.75, 18.25, 19.75, 21.25, 22.75, 24.25,
 25.75,
 9.5, 11, 12.5, 14, 15.5, 17, 18.5, 20, 21.5, 23, 24.5, 26,
 9.75, 11.25, 12.75, 14.25, 15.75, 17.25, 18.75, 20.25, 21.75, 23.25, 24.75,
 26.25,
 10, 11.5, 13, 14.5, 16, 17.5, 19, 20.5, 22, 23.5, 25, 26.5,
 10.25, 11.75, 13.25, 14.75, 16.25, 17.75, 19.25, 20.75, 22.25, 23.75,
 25.25
 對於上面的數據,就是
 latitude = 25,longitude = -125時,pressure = 900,temperature =  9;
 latitude = 25,longitude = -120時,pressure = 906,temperature =  10.5;
 以此類推。
 
4、netcdf文件的讀寫
   「學以至用」 ,前面講的都是netcdf的基本知識,都是爲了本節的核心問題——讀寫netcdf格式的文件
作鋪墊之用,下面咱們就來看看如何創建一個netcdf格式文件,以及如何再讀出它的內容。
一、在命令行下讀寫netcdf文件
  ⑴創建一個simple_xy.cdl文件,內容就是上一節「CDL結構」中的第一個例子。
  ⑵用ncgen.exe工具(下載地址見前面的第二節)創建netcdf文件
    ①將ncgen所在目錄加到系統path變量中或者直接將ncgen.exe拷到simple_xy.cdl所在目錄下
    ②執行ncgen -o simple_xy.nc simple_xy.cdl生成netcdf格式文件simple_xy.nc
  ⑶生成的simple_xy.nc是一個二進制文件,要想從這個文件中還原出數據信息,就要用ncdump工具
     ①將ncdump所在目錄加到系統path變量中或者直接將ncdump.exe拷到simple_xy.nc所在目錄下
     ②在命令行下執行ncdump simple_xy.nc,這時屏幕的輸出和simple_xy.cdl內容徹底同樣。說明
     咱們的文件讀寫操做都是正確的。
 
二、編程讀寫netcdf文件
 前面咱們知道如何手工去創建和讀取netddf文件,下面咱們來看看如何在程序中用代碼實現netcdf
文件的創建和分析。個人編程環境爲win2000+vc6.0 並安裝了vc sp6補丁包。例子代碼選自
netcdf教程中的2.1節The simple xy Example
⑴將netcdf的源代碼解壓。咱們將用到裏面的libsrc/netcdf.h頭文件
⑵在vc6中創建一個空的win32控制檯項目.名字爲SimpleXyWrite,這個項目用來創建netcdf文件
⑶把以下文件拷貝到項目目錄中
①netcdf源代碼中的libsrc/netcdf.h頭文件
②netcdf源代碼中的examples/C/simple_xy_wr.c文件,並更名爲simple_xy_wr.cpp
③netcdf預編譯包中的netcdf.dll文件和 netcdf.lib文件
⑷把netcdf.h文件和simple_xy_wr.cpp加入到項目的文件列表中
  (具體菜單操做project->add to project->files)
⑸把netcdf.lib加入到項目的lib列表中
 (具體菜單操做project->add to project->settings->Link->object/library modules)
⑹編譯並運行這個項目,會在項目目錄下生成一個simple_xy.nc文件,其內容和咱們手工生成的
文件內容徹底同樣。windows

simple_xy_wr.c文件是創建netcdf文件的c代碼,而examples/C/simple_xy_rd.c文件則是分析
netcdf文件的代碼,讀者能夠用和剛纔相似的步驟在vc6中編譯這個文件。運行時把把剛纔生成的
simple_xy.nc拷貝到項目的目錄下,若是文件格式沒錯誤,會提示
*** SUCCESS reading example file simple_xy.nc!
而後退出。api

三、用ncgen命令自動生成c代碼
  給定了simple_xy.cdl文件後,能夠用
  ncgen -c  simple_xy.cdl
  命令直接在屏幕上輸出c代碼.
  不過,這個辦法只限於cdl的數據比較簡單時才能夠採用。對於真正的項目,
  是須要咱們本身去編寫代碼的。
  
5、小結
 經過以上內容的介紹,相信讀者對netcdf已經有了大體的瞭解。整體來講,
netcdf的核心內容就是經過cdl描述文法來創建一個netcdf格式文件。抓住了這一點,
讀者再繼續深刻看netcdf的其餘資料時,應該就沒什麼太大的難度了。如是,做者的
目的也就達到了。數組

6、附錄
爲便於讀者對照,現本文中用到的幾個文件的內容在此列出
一、simple_xy.cdl文件的內容
netcdf simple_xy {
dimensions:
x = 6 ;
y = 12 ;
variables:
int data(x, y) ;
data:
data =
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71 ;
}
二、simple_xy-wr.c文件的內容
/* This is part of the netCDF package.
   Copyright 2006 University Corporation for Atmospheric Research/Unidata.
   See COPYRIGHT file for conditions of use.網絡

   This is a very simple example which writes a 2D array of
   sample data. To handle this in netCDF we create two shared
   dimensions, "x" and "y", and a netCDF variable, called "data".函數

   This example demonstrates the netCDF C API. This is part of the
   netCDF tutorial, which can be found at:
   http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial工具

   Full documentation of the netCDF C API can be found at:
   http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

   $Id: simple_xy_wr.c,v 1.12 2007/02/14 20:59:21 ed Exp $
*/
#include <stdlib.h>
#include <stdio.h>
#include <netcdf.h>

/* This is the name of the data file we will create. */
#define FILE_NAME "simple_xy.nc"

/* We are writing 2D data, a 6 x 12 grid. */
#define NDIMS 2
#define NX 6
#define NY 12

/* Handle errors by printing an error message and exiting with a
 * non-zero status. */
#define ERRCODE 2
#define ERR(e) {printf("Error: %s/n", nc_strerror(e)); exit(ERRCODE);}

int
main()
{
   /* When we create netCDF variables and dimensions, we get back an
    * ID for each one. */
   int ncid, x_dimid, y_dimid, varid;
   int dimids[NDIMS];

   /* This is the data array we will write. It will be filled with a
    * progression of numbers for this example. */
   int data_out[NX][NY];

   /* Loop indexes, and error handling. */
   int x, y, retval;

   /* Create some pretend data. If this wasn't an example program, we
    * would have some real data to write, for example, model
    * output. */
   for (x = 0; x < NX; x++)
      for (y = 0; y < NY; y++)
  data_out[x][y] = x * NY + y;

   /* Always check the return code of every netCDF function call. In
    * this example program, any retval which is not equal to NC_NOERR
    * (0) will cause the program to print an error message and exit
    * with a non-zero return code. */

   /* Create the file. The NC_CLOBBER parameter tells netCDF to
    * overwrite this file, if it already exists.*/
   if ((retval = nc_create(FILE_NAME, NC_CLOBBER, &ncid)))
      ERR(retval);

   /* Define the dimensions. NetCDF will hand back an ID for each. */
   if ((retval = nc_def_dim(ncid, "x", NX, &x_dimid)))
      ERR(retval);
   if ((retval = nc_def_dim(ncid, "y", NY, &y_dimid)))
      ERR(retval);

   /* The dimids array is used to pass the IDs of the dimensions of
    * the variable. */
   dimids[0] = x_dimid;
   dimids[1] = y_dimid;

   /* Define the variable. The type of the variable in this case is
    * NC_INT (4-byte integer). */
   if ((retval = nc_def_var(ncid, "data", NC_INT, NDIMS, 
       dimids, &varid)))
      ERR(retval);

   /* End define mode. This tells netCDF we are done defining
    * metadata. */
   if ((retval = nc_enddef(ncid)))
      ERR(retval);

   /* Write the pretend data to the file. Although netCDF supports
    * reading and writing subsets of data, in this case we write all
    * the data in one operation. */
   if ((retval = nc_put_var_int(ncid, varid, &data_out[0][0])))
      ERR(retval);

   /* Close the file. This frees up any internal netCDF resources
    * associated with the file, and flushes any buffers. */
   if ((retval = nc_close(ncid)))
      ERR(retval);

   printf("*** SUCCESS writing example file simple_xy.nc!/n");
   return 0;
}

三、simple_xy_rd.c文件的內容
/* This is part of the netCDF package.
   Copyright 2006 University Corporation for Atmospheric Research/Unidata.
   See COPYRIGHT file for conditions of use.

   This is a simple example which reads a small dummy array, which was
   written by simple_xy_wr.c. This is intended to illustrate the use
   of the netCDF C API.

   This program is part of the netCDF tutorial:
   http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

   Full documentation of the netCDF C API can be found at:
   http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

   $Id: simple_xy_rd.c,v 1.9 2006/08/17 23:00:55 russ Exp $
*/
#include <stdlib.h>
#include <stdio.h>
#include <netcdf.h>

/* This is the name of the data file we will read. */
#define FILE_NAME "simple_xy.nc"

/* We are reading 2D data, a 6 x 12 grid. */
#define NX 6
#define NY 12

/* Handle errors by printing an error message and exiting with a
 * non-zero status. */
#define ERRCODE 2
#define ERR(e) {printf("Error: %s/n", nc_strerror(e)); exit(ERRCODE);}

int
main()
{
   /* This will be the netCDF ID for the file and data variable. */
   int ncid, varid;

   int data_in[NX][NY];

   /* Loop indexes, and error handling. */
   int x, y, retval;

   /* Open the file. NC_NOWRITE tells netCDF we want read-only access
    * to the file.*/
   if ((retval = nc_open(FILE_NAME, NC_NOWRITE, &ncid)))
      ERR(retval);

   /* Get the varid of the data variable, based on its name. */
   if ((retval = nc_inq_varid(ncid, "data", &varid)))
      ERR(retval);

   /* Read the data. */
   if ((retval = nc_get_var_int(ncid, varid, &data_in[0][0])))
      ERR(retval);

   /* Check the data. */
   for (x = 0; x < NX; x++)
      for (y = 0; y < NY; y++)
  if (data_in[x][y] != x * NY + y)
     return ERRCODE;

   /* Close the file, freeing all resources. */
   if ((retval = nc_close(ncid)))
      ERR(retval);

   printf("*** SUCCESS reading example file %s!/n", FILE_NAME);   return 0;}

相關文章
相關標籤/搜索