首页 > 其他分享 >气象NC扇形经纬网格转换成前端要求的等经纬网格_cwr888的博客

气象NC扇形经纬网格转换成前端要求的等经纬网格_cwr888的博客

时间:2022-10-12 18:57:50浏览次数:70  
标签:float ArrayFloat Attribute NC 经纬网格 addAttribute cwr888 new D2

气象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

相关文章