NetCDF全稱為network Common Data Format,中文譯法為“網絡通用數據格式”,對程序員來說,它和zip、jpeg、bmp文件格式類似,都是一種文件格式的標准。netcdf文件開始的目的是用於存儲氣象科學中的數據,現在已經成為許多數據采集軟件的生成文件的格式。
從數學上來說,netcdf存儲的數據就是一個多自變量的單值函數。用公式來說就是f(x,y,z,…)=value, 函數的自變量x,y,z等在netcdf中叫做維(dimension) 或坐標軸(axix),函數值value在netcdf中叫做變量(Variables).而自變量和函數值在物理學上的一些性質,比如計量單位(量綱)、物理學名稱等等
1、變量(Variables)
變量對應着真實的物理數據。比如我們家里的電表,每個時刻顯示的讀數表示用戶的到該時刻的耗電量。這個讀數值就可以用netcdf里的變量來表示。它是一個以時間為自變量(或者說自變量個數為一維)的單值函數。再比如在氣象學中要作出一個氣壓圖,就是“東經xx度,北緯yy度的點的大氣壓值為多少帕”,這是一個二維單值函數,兩維分別是經度和緯度。函數值為大氣壓。
從上面的例子可以看出,netcdf中的變量就是一個N維數組,數組的維數就是實際問題中的自變量個數,數組的值就是觀測得到的物理值。變量(數組值)在netcdf中的存儲類型有六種,ascii字符(char) ,字節(byte), 短整型(short), 整型(int), 浮點(float), 雙精度(double). 顯然這些類型和c中的類型一致,搞C的朋友應該很快就能明白。
2、維(dimension)
一個維對應着函數中的某個自變量,或者說函數圖象中的一個坐標軸,在線性代數中就是一個N維向量的一個分量(這也是維這個名稱的由來)。在netcdf中,一個維具有一個名字和范圍(或者說長度,也就是數學上所說的定義域,可以是離散的點集合或者連續的區間)。在netcdf中,維的長度基本都是有限的,最多只能有一個具有無限長度的維,例如:
dimensions:
time = 1;
isobaric = 1;
lat = 281;
lon = 361;
3、屬性(Attribute)
屬性對變量值和維的具體物理含義的注釋或者說解釋。因為變量和維在netcdf中都只是無量綱的數字,要想讓人們明白這些數字的具體含義,就得靠屬性這個對象了。 在netcdf中,屬性由一個屬性名和一個屬性值(一般為字符串)組成。例如:
***
variables:
float longitude(lon=361);
:units = "degrees_east";
float latitude(lat=281);
:units = "degrees_north";***
*** variables: float longitude(lon=361); :units = "degrees_east"; float latitude(lat=281); :units = "degrees_north";***
float是變量類型,longitude時一個定義好的Variables變量,即經度,:units=“degrees_east”;組成一個屬性,units為屬性名,degrees_east為屬性值。
package com.DateRW;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ucar.ma2.ArrayFloat;
import ucar.ma2.ArrayInt;
import ucar.ma2.DataType;
import ucar.ma2.Index;
import ucar.ma2.InvalidRangeException;
import ucar.nc2.Attribute;
import ucar.nc2.Dimension;
import ucar.nc2.NetcdfFile;
import ucar.nc2.NetcdfFileWriter;
import ucar.nc2.Variable;
import ucar.nc2.NetcdfFileWriter.Version;
/**
* 將grib數據用NC存儲
* @author EncodingKing
* @date 2020-4-8
*
*/
public class grib_nc {
public static void main(String[] args) {
//讀取grib文件路徑
String gribPath="E:Grib\\C4U\\W_NAFP_C_ECMF_20200307200247_P_C4U03071200032212001";
//存儲NC文件路徑
String NcPath="E:Grib\\C4U\\gripNc2";
try {
NetcdfFile openGrib=NetcdfFile.open(gribPath);
//獲取time變量
Variable time=openGrib.findVariable("time");
double[] dateTime=(double[]) time.read().copyTo1DJavaArray();
//獲取經度
Variable lon=openGrib.findVariable("lon");
float[] dateLon=(float[]) lon.read().copyTo1DJavaArray();
//獲取緯度
Variable lat=openGrib.findVariable("lat");
float[] dateLat=(float[]) lat.read().copyTo1DJavaArray();
//獲取有效波高變量
Variable Significant_wave_heigh=openGrib.findVariable("Significant_wave_height_of_at_least_6_m_msl_120_Hour_2");
//獲取時間經緯度數組的長度
int dateTimeL=dateTime.length;
int dateLonL=dateLon.length;
int dateLatL=dateLat.length;
//將有效波高變量放到三維數組中
float[][][] threeArr=(float[][][]) Significant_wave_heigh.read().copyToNDJavaArray();
System.out.println("arrD.length="+threeArr.length+" arrD[0].length="+
threeArr[0].length + " arrD[0][0].length="+threeArr[0][0].length);
//拼接NC文件路徑
NetcdfFileWriter fileWriter = NetcdfFileWriter.createNew(Version.netcdf3, NcPath+".nc");
//創建一維自變量
Dimension timeDim=fileWriter.addDimension(null, "time", dateTimeL);
Dimension latDim=fileWriter.addDimension(null, "lat", dateLatL);
Dimension lonDim=fileWriter.addDimension(null, "lon", dateLonL);
//將一維合成二維list
ArrayList<Dimension> dim=new ArrayList<>();
//與前邊定義的一維自變量順序保持一致
dim.add(timeDim);
dim.add(latDim);
dim.add(lonDim);
// 創建名稱為lon的變量,類型為folat,對應的維度為lon,對應Dimension里面定義的名稱為"lon"
Variable vx = fileWriter.addVariable(null, "lon", DataType.FLOAT,
"lon");
List<Attribute> attributesLon = lon.getAttributes();
for (int i = 0; i < attributesLon.size(); i++) {
String[] strResut = attributesLon.get(i).toString().split("=");
fileWriter.addVariableAttribute(vx, new Attribute(strResut[0].trim(),
strResut[1].replace("\"", "").trim()));
}
// 創建名稱為lat的變量,類型為folat,對應Dimension里面定義的名稱為"lat"
Variable vy = fileWriter.addVariable(null, "lat", DataType.FLOAT,
"lat");
List<Attribute> attributesLat = lat.getAttributes();
for (int i = 0; i < attributesLat.size(); i++) {
String[] strResut = attributesLat.get(i).toString().split("=");
fileWriter.addVariableAttribute(vy, new Attribute(strResut[0].trim(),
strResut[1].replace("\"", "").trim()));
}
// 創建名稱為time的變量,類型為double,對應Dimension里面定義的名稱為"time"
Variable vt = fileWriter.addVariable(null, "time", DataType.DOUBLE,
"time");
List<Attribute> attributesTime = time.getAttributes();
for (int i = 0; i < attributesTime.size(); i++) {
String[] strResut = attributesTime.get(i).toString().split("=");
fileWriter.addVariableAttribute(vt, new Attribute(strResut[0].trim(),
strResut[1].replace("\"", "").trim()));
}
// 創建變量名稱為value的變量,對應的維度為dims,
Variable v = fileWriter.addVariable(null, "value", DataType.FLOAT,
dim);
List<Attribute> attributesD = Significant_wave_heigh.getAttributes();
for (int i = 0; i < attributesD.size(); i++) {
String[] strResut = attributesD.get(i).toString().split("=");
fileWriter.addVariableAttribute(v, new Attribute(strResut[0].trim(),
strResut[1].replace("\"", "").trim()));
}
List<Attribute> globalAttributes = openGrib.getGlobalAttributes();
for (int i = 0; i < globalAttributes.size(); i++) {
String[] strResut = globalAttributes.get(i).toString().split("=");
fileWriter.addGroupAttribute(null, new Attribute(strResut[0].trim(),
strResut[1].replace("\"", "").trim()));
}
//創建文件
fileWriter.create();
//設置一維變量
ArrayInt timeValues = new ArrayInt.D1(dateTimeL);
ArrayFloat latValues = new ArrayFloat.D1(dateLatL);
ArrayFloat lonValues = new ArrayFloat.D1(dateLonL);
//設置三維變量
ArrayFloat values=new ArrayFloat.D3(dateTimeL, dateLatL, dateLonL);
//設置索引
Index index = values.getIndex();
for(int a=0;a<dateTimeL;a++){
//給time變量賦值,此處的值是從dateTime[]數組中取出的。
timeValues.setDouble(a, dateTime[a]);
for(int b=0;b<dateLatL;b++){
//給lat賦值
latValues.setFloat(b, dateLat[b]);
for(int c=0;c<dateLonL;c++){
//給lon賦值
lonValues.setFloat(c, dateLon[c]);
//將threeArr[][][]三維數組中的值,對應index.set(a, b, c)坐標放入;
values.setDouble(index.set(a, b, c), threeArr[a][b][c]);
}
}
}
fileWriter.write(vt, timeValues);
fileWriter.write(vy, latValues);
fileWriter.write(vx, lonValues);
fileWriter.write(v, values);
fileWriter.close();
System.out.println("文件已存入" + NcPath);
} catch (InvalidRangeException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
轉成NC后的結果:
netcdf file:/E:/Grib/C4U/gripNc2.nc {
dimensions:
time = 1;
lat = 361;
lon = 720;
variables:
float lat(lat=361);
:units = "degrees_north";
float lon(lon=720);
:units = "degrees_east";
int time(time=1);
:units = "Hour since 2020-03-07T12:00:00Z";
:standard_name = "time";
:long_name = "GRIB forecast or observation time";
:calendar = "proleptic_gregorian";
:bounds = "time_bounds";
float value(time=1, lat=361, lon=720);
:long_name = "Significant wave height of at least 6 m (120_Hour) @ Mean sea level";
:units = "%";
:description = "Cloud water";
:missing_value = "NaNf";
:grid_mapping = "LatLon_Projection";
:coordinates = "reftime time lat lon";
:Grib_Statistical_Interval_Type = "2";
:Grib_Variable_Id = "VAR_98-0-131-76_L102_I120_Hour_S2";
:Grib1_Center = "98";
:Grib1_Subcenter = "0";
:Grib1_TableVersion = "131";
:Grib1_Parameter = "76";
:Grib1_Parameter_Name = "swhg6";
:Grib1_Level_Type = "102";
:Grib1_Level_Desc = "Mean sea level";
:Grib1_Interval_Type = "2";
:Grib1_Interval_Name = "product valid, interval";
// global attributes:
:Originating_or_generating_Center = "European Centre for Medium Range Weather Forecasts (ECMWF) (RSMC)";
:Originating_or_generating_Subcenter = "0";
:GRIB_table_version = "0,131";
:file_format = "GRIB-1";
:Conventions = "CF-1.6";
:history = "Read using CDM IOSP GribCollection v3";
:featureType = "GRID";
}
讀取grib/NC數據所需的netcdfall-4.6.11.jar
原文鏈接:https://blog.csdn.net/weixin_44553640/java/article/details/105465714