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