1. 程式人生 > >NC檔案讀寫方式

NC檔案讀寫方式

概述

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).

netcdf檔案的內容

一個netcdf檔案的結構包括以下物件:
1、變數(Variables)
變數對應著真實的物理資料。比如我們家裡的電錶,每個時刻顯示的讀數表示使用者的到該時刻的耗電量。這個讀數值就可以用netcdf裡的變數來表示。它是一個以時間為自變數(或者說自變數個數為一維)的單值函式。再比如在氣象學中要作出一個氣壓圖,就是“東經xx度,北緯yy度的點的大氣壓值為多少帕”,這是一個二維單值函式,兩維分別是經度和緯度。函式值為大氣壓。

從上面的例子可以看出,netcdf中的變數就是一個N維陣列,陣列的維數就是實際問題中的自變數個數,陣列的值就是觀測得到的物理值。變數(陣列值)在netcdf中的儲存型別有六種,ascii字元(char) ,位元組(byte), 短整型(short), 整型(int), 浮點(float), 雙精度(double). 顯然這些型別和c中的型別一致,搞C的朋友應該很快就能明白。

2、維(dimension)
一個維對應著函式中的某個自變數,或者說函式圖象中的一個座標軸,線上性代數中就是一個N維向量的一個分量(這也是維這個名稱的由來)。在netcdf中,一個維具有一個名字和範圍(或者說長度,也就是數學上所說的定義域,可以是離散的點集合或者連續的區間)。在netcdf中,維的長度基本都是有限的,最多隻能有一個具有無限長度的維。

3、屬性(Attribute)
屬性對變數值和維的具體物理含義的註釋或者說解釋。因為變數和維在netcdf中都只是無量綱的數字,要想讓人們明白這些數字的具體含義,就得靠屬性這個物件了。
在netcdf中,屬性由一個屬性名和一個屬性值(一般為字串)組成。比如,在某個cdl檔案(cdl檔案的具體格式在下一節中講述)中有這樣的程式碼段
temperature:units = “celsius” ;
前面的temperature是一個已經定義好的變數(Variable),即溫度,冒號後面的units就是屬性名,表示物理單位,=後面的就是units這個屬性的值,為“celsius” ,即攝氏度,整個一行程式碼的意思就是溫度這個物理量的單位為celsius,很好理解。

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, 這個結構包括三個部分
1、維的定義,以dimensions:關鍵字開頭
dimensions:
x = 6 ;
y = 12 ;
定義了兩個軸(或者說兩維),名字分別為x和y,x軸的長度(準確的說是座標點的個數)為6, y軸的長度為12。

2、變數的定義:以variables:開頭
variables:
int data(x, y);
定義了一個以x軸和y軸為自變數的函式data,數學公式就是f(x,y)=data;
注意維出現的順序是有序的,它決定data段中的具體賦值結果.

3、資料的定義,以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;

要注意的是,
1、賦值順序:
我們給出的是c格式的cdl檔案,因此這裡的賦值順序和c語言中的一致,也就是通常所說的“行式賦值”,而fortran語言中則是“列式賦值”,因此在fortran格式的cdl檔案中,data段的數值順序和這裡正好行列互換。
2、自變數的預設取值和座標變數
如果只給出維的長度,那麼維的值預設從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;
以此類推。

檔案讀寫

一次只讀取一層

如果CONC是一個7維的變數,為了節省空間,如果每一次只讀取一層,方法如下所示
int[] start = { 0, 0, 0, 0, 0, 0, 0 }; /* 開始的位置*/
int[] count = { 1, 1, 1, 1, 1, south_northLen, west_eastLen };//每次讀取的陣列大小
start[4] = l;
CONCarraySize = south_northLen * west_eastLen;
float[] CONC = new float[CONCarraySize];//DRYDEP和WETDEP大小是一樣的
NetCDF.nc_get_vara_float(ncid, CONCid, start, count, CONC);

一次將所有的資料均讀取出來

 float[] U10 = new float[south_northLen * west_eastLen];
 float[] V10 = new float[south_northLen * west_eastLen];
 NetCDF.nc_inq_varid(ncid, "U10", out Uid);
 NetCDF.nc_inq_varid(ncid, "V10", out Vid);

 NetCDF.nc_get_var_float(ncid, Uid, U10);
 NetCDF.nc_get_var_float(ncid, Vid, V10);