1、操作nc文件
//12ceng
public static void readERA5NcDuoCeng(String inputFile,int ceng) {
String outputFile="E://Pic/chenxia/不同高度风数据/output/";
int point=2;
double lonSize=0.125;
double latSize=-0.125;
NetcdfFile openNC = null;
try {
openNC = NetcdfFile.open(inputFile);
Variable dataU = openNC.findVariable("u");
Variable dataV = openNC.findVariable("v");
Variable Lat=openNC.findVariable("latitude");
Variable Lon=openNC.findVariable("longitude");
Variable Level=openNC.findVariable("level");
Variable time=openNC.findVariable("time");
float[] arrLat=(float[]) Lat.read().copyTo1DJavaArray();
float[] arrLon=(float[]) Lon.read().copyTo1DJavaArray();
int[] arrLevel=(int[]) Level.read().copyTo1DJavaArray();
int latCount=arrLat.length;
int lonCount=arrLon.length;
int levelCount=arrLevel.length;
BigDecimal b=new BigDecimal(arrLon[0]);
double dBeginLon=b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
b=new BigDecimal(arrLat[0]);
double dBeginLat=b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
b=new BigDecimal(arrLat[latCount-1]);
double dEndLat=b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
b=new BigDecimal(arrLon[lonCount-1]);
double dEndLon=b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
double u_scale_factor=0,u_add_offset=0;
List<Attribute> uAttr = dataU.getAttributes();
for (Attribute attribute : uAttr) {
if(attribute.getShortName().equals("scale_factor")) {
Array aString = attribute.getValues();
u_scale_factor=aString.getDouble(0);
}
else if(attribute.getShortName().equals("add_offset")) {
Array aString = attribute.getValues();
u_add_offset=aString.getDouble(0);
}
}
double v_scale_factor=0,v_add_offset=0;
List<Attribute> vAttr = dataV.getAttributes();
for (Attribute attribute : vAttr) {
if(attribute.getShortName().equals("scale_factor")) {
Array aString = attribute.getValues();
v_scale_factor=aString.getDouble(0);
}
else if(attribute.getShortName().equals("add_offset")) {
Array aString = attribute.getValues();
v_add_offset=aString.getDouble(0);
}
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
Calendar calendar=Calendar.getInstance();
int[] arrTime=(int[]) time.read().copyTo1DJavaArray();
for(int m=0;m<levelCount;m++) {
if(arrLevel[m]!=ceng) {
continue;
}
for (int j = 0; j < arrTime.length; j++) {
int t = arrTime[j];
calendar.setTime(sdf.parse("1900-01-01 00:00:00"));
calendar.add(Calendar.HOUR, t);
String forecastDate=new SimpleDateFormat("yyyyMMdd000000").format(calendar.getTime());
short[][] arrU= (short[][])dataU.read(new int [] {j,m,0,0},new int [] {1,1,latCount,lonCount}).reduce().copyToNDJavaArray();
short[][] arrV= (short[][])dataV.read(new int [] {j,m,0,0},new int [] {1,1,latCount,lonCount}).reduce().copyToNDJavaArray();
double[][] arrDoubleU=new double[latCount][lonCount];
for(int x=0;x<latCount;x++) {
for(int y=0;y<lonCount;y++) {
if(arrU[x][y]==-32767) {
arrDoubleU[x][y]=-32767;
}else {
arrDoubleU[x][y]=arrU[x][y]*u_scale_factor+u_add_offset;
}
}
}
double[][] arrDoubleV=new double[latCount][lonCount];
for(int x=0;x<latCount;x++) {
for(int y=0;y<lonCount;y++) {
if(arrV[x][y]==-32767) {
arrDoubleV[x][y]=-32767;
}else {
arrDoubleV[x][y]=arrV[x][y]*v_scale_factor+v_add_offset;
}
}
}
}
}
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
openNC.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2、操作grib2文件
public SmartGridForecastModel readData(String filePath, double beginLon, double beginLat, double endLon, double endLat, int[] arrForecastTime) throws Exception {
NetcdfFile netcdfFile = null;
try {
// 打开文件
netcdfFile = NetcdfFile.open(filePath,null);
// 获取变量
Variable varLon = netcdfFile.findVariable(lonFieldText);
Variable varLat = netcdfFile.findVariable(latFieldText);
Variable varTime = netcdfFile.findVariable(timeFieldText);
Variable varData = netcdfFile.findVariable(dataFieldText);
if (varLon == null || varLat == null || varTime == null || varData == null) {
return null;
}
// 定义文件头和数据体
SmartGridForecastHeader header = new SmartGridForecastHeader();
List<SmartGridForecastData> listData = new ArrayList<SmartGridForecastData>();
float[] arrLon = (float[]) varLon.read().copyTo1DJavaArray();
float[] arrLat = (float[]) varLat.read().copyTo1DJavaArray();
int[] arrTime = (int[]) varTime.read().copyTo1DJavaArray();
int beginY= Arrays.binarySearch(arrLat, (float)beginLat);
int beginX= Arrays.binarySearch(arrLon, (float)beginLon);
int endY= Arrays.binarySearch(arrLat, (float)endLat);
int endX= Arrays.binarySearch(arrLon, (float)endLon);
// 获取符合经纬度范围、时次条件的数据
if (arrForecastTime == null) {
arrForecastTime = arrTime;
}
int[] size = new int[] { 1, endX-beginX, endY-beginY };
for (int forecastTime : arrForecastTime) {
// 寻找时次
int timeStart = -1;
for (int i = 0; i < arrTime.length; i++) {
if (arrTime[i] == forecastTime) {
timeStart = i;
break;
}
}
if (timeStart == -1) {
continue;
}
int[] origin = new int[] { timeStart, beginX, beginY }; // 第一维的timeStart开始,第二维从0开始,第三维从0开始
float[] arrData = (float[]) varData.read(origin, size).copyTo1DJavaArray();
int rowIndex = 0;
int dataIndex = 0;
for (int latIndex = beginY; latIndex < endY; latIndex++) {
double lat = DataConvert.toDouble(arrLat[latIndex], 2);
boolean hasRow = false;
int colIndex = 0;
for (int lonIndex = beginX; lonIndex < endX; lonIndex++) {
double lon = DataConvert.toDouble(arrLon[lonIndex], 2);
// 找到的点数据
SmartGridForecastData data = new SmartGridForecastData();
data.setForecastTime(forecastTime);
data.setLon(Float.parseFloat(String.valueOf(lon)));
data.setLat(Float.parseFloat(String.valueOf(lat)));
data.setRowIndex(rowIndex);
data.setColIndex(colIndex);
data.setValue(arrData[dataIndex]);
listData.add(data);
hasRow = true;
colIndex++;
dataIndex++;
}
if (hasRow) {
header.setColCount(colIndex);
rowIndex++;
}
}
header.setRowCount(rowIndex);
}
if (listData.size() > 0) {
header.setBeginLon(Double.parseDouble(String.valueOf(listData.get(0).getLon())));
header.setBeginLat(Double.parseDouble(String.valueOf(listData.get(0).getLat())));
}
header.setGridSize(DataConvert.toDouble(arrLon[1] - arrLon[0], 2));
header.setArrForecastTime(arrForecastTime);
// 结果集
SmartGridForecastModel sgfm = new SmartGridForecastModel();
sgfm.setHeader(header);
sgfm.setData(listData);
return sgfm;
} catch (Exception e) {
throw e;
} finally {
netcdfFile.close();
}
}
3、实现双线性插值方法
/**
将格点数据转换为站点数据,取值为双线性插值。
注意:传入的开始经纬、纬度,须匹配二维数组的实际情况,过大或过小都导致转换偏差。
@param arrValue 格点行、列数组。
@param listStation 站点集合,需包含站号、经度、纬度。
@param beginLon 格点集合的起始经度。
@param beginLat 格点集合的起始纬度。
@param lonSize 经度格点集合的分辨率,1公里则设置0.01。
@param latSize 纬度格点集合的分辨率,1公里则设置0.01。
@return 新的站点集合。
*/
public List<StationPoint> convertGridPointToStationPointByBilinear(double[][] arrValue, List<StationPoint> listStation, double beginLon, double beginLat, double lonSize, double latSize){
//复制一份 listStation
List<StationPoint> list = new ArrayList<StationPoint>(listStation.size());
for (int i = 0; i < listStation.size(); i++) {
StationPoint sp = (StationPoint) listStation.get(i).clone();
list.add(sp);
}
int maxRowIndex = arrValue.length - 1;
int maxColIndex = arrValue[0].length - 1;
for (StationPoint station : list){
double rowIndexDouble = (station.getLat() - beginLat) / latSize;
double colIndexDouble = (station.getLon() - beginLon) / lonSize;
int rowIndexInt = (int)Math.floor(rowIndexDouble);
int colIndexInt = (int)Math.floor(colIndexDouble);
if (rowIndexInt >= maxRowIndex){
rowIndexInt = maxRowIndex-1;
}
if (colIndexInt >= maxColIndex){
colIndexInt = maxColIndex-1;
}
double valueLeftUp = (rowIndexDouble - rowIndexInt) * (colIndexDouble - colIndexInt);
double valueRightUp = (rowIndexInt + 1 - rowIndexDouble) * (colIndexDouble - colIndexInt);
double valueRightDown = (rowIndexInt + 1 - rowIndexDouble) * (colIndexInt + 1 - colIndexDouble);
double valueLeftDown = (rowIndexDouble - rowIndexInt) * (colIndexInt + 1 - colIndexDouble);
try {
station.setValue(arrValue[rowIndexInt][colIndexInt] * valueRightDown + arrValue[rowIndexInt + 1][colIndexInt] * valueLeftDown + arrValue[rowIndexInt + 1][colIndexInt + 1] * valueLeftUp + arrValue[rowIndexInt][colIndexInt + 1] * valueRightUp);
} catch (Exception e) {
System.out.println(station.getLat()+","+station.getLon());
e.printStackTrace();
}
}
return list;
}