气象NC扇形经纬网格转换成前端leaflet-vector-scalar.js要求的等经纬网格
背景:最近从气象局拿到文件格式为NC的气象文件(包括温度、湿度、风、气压、雨量等),需要读取其中的温度数据并在前端展示。用专业软件打开一看,图是扇形的,经纬度间隔也不相等,如下图:
问题:需要读文件格式为NC的气象文件中的温度数据,并转换为leaflet-vector-scalar.js要求的等经纬网格JSON数据。
解决:通过JAVA调用netcdf包读取NC文件,将NC扇形经纬网格转换成等经纬网格,转换思路如下:
将扇形经纬网格1、2、3、4(红色格)数值相加求平均值,赋值给等经纬网格a(黑色格)实现JAVA代码如下:
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import ucar.ma2.ArrayFloat;
import ucar.ma2.DataType;
import ucar.nc2.*;
public class CreateNetCDF_2D_TEMP {
public final static float MISSING_VALUE = -9.96921E36f;
public final static String TMP_DIR = "D:/";
public static void main(String[] args) throws Exception {
//last 'aa' is 'AM' or 'PM'. 'HH' is 24 hour system. if you change it to 'hh', it means 12 hour system
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss aa");
NetcdfFile ncfile = null;
NetcdfFileWriter writer = null;
//自定义等间距网格数
int xGridsNum = 350;
int yGridsNum = 300;
try {
ncfile = NetcdfFile.open("d:/temp.nc");
// Get the latitude and longitude Variables.
Variable latVarO = ncfile.findVariable("NLAT");
Variable lonVarO = ncfile.findVariable("ELON");
// Get the temperature Variables.
Variable tmpVariable = ncfile.findVariable("TMP");
ArrayFloat.D2 latArray;
ArrayFloat.D2 lonArray;
ArrayFloat.D2 tmpArray;
latArray = (ArrayFloat.D2) latVarO.read();
lonArray = (ArrayFloat.D2) lonVarO.read();
tmpArray = (ArrayFloat.D2) tmpVariable.read();
//Calculate latitude and longitude range
float minLat = 99999f, maxLat = 0f;
float minLon = 99999f, maxLon = 0f;
int latGridsNumO = latVarO.getDimension(0).getLength();
int lonGridsNumO = latVarO.getDimension(1).getLength();
//使用原始NC数据中网格数
//xGridsNum = latGridsNumO;
//yGridsNum = lonGridsNumO;
//Calculate temperature range
float minTmp = 99999f, maxTmp = 0f;
for(int j=0;j<lonGridsNumO;j++) {
for(int i=0; i<latGridsNumO; i++) {
float fLat = latArray.get(i,j);
float fLon = lonArray.get(i,j);
float fTemp = tmpArray.get(i,j);
//latData.set(i,j, f);
//lonData.set(i,j, f);
if(maxLat<fLat) maxLat = fLat;
if(minLat>fLat) minLat = fLat;
if(maxLon<fLon) maxLon = fLon;
if(minLon>fLon) minLon = fLon;
if(maxTmp<fTemp) maxTmp = fTemp;
if(minTmp>fTemp) minTmp = fTemp;
}
}
System.out.println("lo1:" + minLon);
System.out.println("lo2:" + maxLon);
System.out.println("la1:" + maxLat);
System.out.println("la2:" + minLat);
System.out.println("nx:" + xGridsNum);
System.out.println("ny:" + yGridsNum);
System.out.println("minTEMP:" + minTmp);
System.out.println("maxTEMP:" + maxTmp);
//定义新的NC文件
String varname = "temp0";
writer = NetcdfFileWriter.createNew(NetcdfFileWriter.Version.netcdf3, TMP_DIR+varname+".nc");
//经度纬度维度定义
Dimension latDimension = writer.addDimension(null, "lat", yGridsNum);
Dimension lonDimension = writer.addDimension(null, "lon", xGridsNum);
//纬度变量属性设置
Variable latVar = writer.addVariable(null, "lat", DataType.FLOAT, Arrays.asList(lonDimension,latDimension));
latVar.addAttribute(new Attribute("units", "Degrees_north"));
latVar.addAttribute(new Attribute("description", "Latitude"));
latVar.addAttribute(new Attribute("long_name", "Latitude"));
latVar.addAttribute(new Attribute("standard_name", "latitude"));
latVar.addAttribute(new Attribute("axis", "Y"));
latVar.addAttribute(new Attribute("coordinate_defines", "center"));
latVar.addAttribute(new Attribute("actual_range",Arrays.asList(minLat, maxLat)));
//经度变量属性设置
Variable lonVar = writer.addVariable(null, "lon", DataType.FLOAT, Arrays.asList(lonDimension,latDimension));
lonVar.addAttribute(new Attribute("units", "Degrees_east"));
lonVar.addAttribute(new Attribute("description", "Longitude"));
lonVar.addAttribute(new Attribute("long_name", "Longitude"));
lonVar.addAttribute(new Attribute("standard_name", "longitude"));
lonVar.addAttribute(new Attribute("axis", "X"));
lonVar.addAttribute(new Attribute("coordinate_defines", "center"));
lonVar.addAttribute(new Attribute("actual_range",Arrays.asList(minLon, maxLon)));
//温度变量属性设置
Variable tempVar = writer.addVariable(null, varname, DataType.FLOAT, Arrays.asList(lonDimension,latDimension));
tempVar.addAttribute(new Attribute("units", "degK"));
tempVar.addAttribute(new Attribute("description", "Temperature temp"));
tempVar.addAttribute(new Attribute("missing_value", MISSING_VALUE));
tempVar.addAttribute(new Attribute("dataset", "NOAA/NCEP GHCN CAMS"));
tempVar.addAttribute(new Attribute("var_desc", "Air Temperature"));
tempVar.addAttribute(new Attribute("valid_range", Arrays.asList(150.0f,400.0f)));
//add global attributes
writer.addGroupAttribute(null, new Attribute("SOUTH-NORTH_GRID_DIMENSION", latDimension.getLength()));
writer.addGroupAttribute(null, new Attribute("WEST-EAST_GRID_DIMENSION", lonDimension.getLength()));
writer.addGroupAttribute(null, new Attribute("TITLE", "NOAA/NCEP GHCN CAMS Monthly Temperature"));
writer.addGroupAttribute(null, new Attribute("Conventions", "CF-1.0"));
//定义新NC文件中经度、纬度、温度变量数组
ArrayFloat.D2 latData = new ArrayFloat.D2(lonDimension.getLength(), latDimension.getLength());
ArrayFloat.D2 lonData = new ArrayFloat.D2(lonDimension.getLength(), latDimension.getLength());
ArrayFloat.D2 tempData = new ArrayFloat.D2(lonDimension.getLength(), latDimension.getLength());
//纬度网格间距
float latLen = Math.abs(maxLat-minLat)/latDimension.getLength();
//经度网格间距
float lonLen = Math.abs(maxLon-minLon)/lonDimension.getLength();
System.out.println("dy:" + latLen);
System.out.println("dx:" + lonLen);
//创建一个线程池
ExecutorService pool = Executors.newCachedThreadPool();
for(int j=0; j<latDimension.getLength(); j++) {
for(int i=0; i<lonDimension.getLength(); i++) {
float tempLat = minLat + j*latLen;
float tempLon = minLon + i*lonLen;
latData.set(i,j, tempLat);
lonData.set(i,j, tempLon);
//Date date0 = new Date();
//System.out.println("线程" + i + "," + j + "开启时间" + sdf.format(date0));
//计算等经纬网格中J,I网格的值
Callable c = new MyCallable(latGridsNumO,lonGridsNumO,latArray,lonArray,
tmpArray,tempLat,tempLon,latLen,lonLen);
//执行任务并获取 Future 对象
Future future = pool.submit(c);
float f = Float.parseFloat(future.get().toString());
tempData.set(i,j, f);
}
}
tempVar.addAttribute(new Attribute("actual_range", Arrays.asList(minTmp, maxTmp)));
// 关闭线程池
pool.shutdown();
//将数组中的数据组装成字符串。数据之间','间隔
String TEMPData = "";
for(int j=latDimension.getLength()-1;j>-1;j--){
for(int i=0;i<lonDimension.getLength();i++) {
if(j==0&&i==lonDimension.getLength()-1){
TEMPData += tempData.get(i,j) + "";
}
else{
TEMPData += tempData.get(i,j) + ",";
}
}
}
//将温度数据写入txt
File file = new File("d:\\outTmp.txt"); //存放数组数据的文件
java.io.FileWriter out = new java.io.FileWriter(file); //文件写入流
out.write(TEMPData);
out.close();
//创建新的NC文件,并写入值
writer.create();
writer.write(latVar, latData);
writer.write(lonVar, lonData);
writer.write(tempVar, tempData);
//打印温度值总数量
System.out.println("Temperature value number:" + tempData.getSize());
//System.out.println(tempData.get(tempData.getSize()-1).toString());
writer.close();
//前端需要返回的参数
// float lo1 = minLon;
// float lo2 = maxLon;
// float la1 = maxLat;
// float la2 = minLat;
// int nx = xGridsNum;
// int ny = yGridsNum;
// float dy = latLen;
// float dx = lonLen;
// String data = TEMPData;
// float minTEMP = minTmp;
// float maxTEMP = maxTmp;
} finally {
ncfile.close();
}
}
}
class MyCallable implements Callable<Object> {
//参数定义
int latGridsNumO;
int lonGridsNumO;
ArrayFloat.D2 latArray;
ArrayFloat.D2 lonArray;
ArrayFloat.D2 tmpArray;
float tempLat;
float tempLon;
float latLen;
float lonLen;
MyCallable(int latGridsNumO,int lonGridsNumO,ArrayFloat.D2 latArray,ArrayFloat.D2 lonArray,
ArrayFloat.D2 tmpArray,float tempLat,float tempLon,float latLen,float lonLen) {
this.latGridsNumO = latGridsNumO;
this.lonGridsNumO = lonGridsNumO;
this.latArray = latArray;
this.lonArray = lonArray;
this.tmpArray = tmpArray;
this.tempLat = tempLat;
this.tempLon = tempLon;
this.latLen = latLen;
this.lonLen = lonLen;
}
public Object call() throws Exception {
float tempTmps = 0f;
int tempNum = 0;
for(int jLat=0; jLat<this.lonGridsNumO; jLat++) {
for (int iLon = 0; iLon < this.latGridsNumO; iLon++) {
if(this.latArray.get(iLon,jLat)>=(tempLat-latLen) &&
this.latArray.get(iLon,jLat)<=(tempLat+latLen) &&
this.lonArray.get(iLon,jLat)>=(tempLon-lonLen) &&
this.lonArray.get(iLon,jLat)<=(tempLon+lonLen)
){
tempNum++;
tempTmps += this.tmpArray.get(iLon,jLat);
}
}
}
float f = 0f;
if(tempNum>0)
{
f = tempTmps/tempNum;
}
return f;
}
}
最终leaflet-vector-scalar.js展示结果如下:
本文转自 https://blog.csdn.net/cwr888/article/details/123359636,如有侵权,请联系删除。
标签:float,ArrayFloat,Attribute,NC,经纬网格,addAttribute,cwr888,new,D2 From: https://www.cnblogs.com/hustshu/p/16785584.html