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

23 篇文章 0 订阅
6 篇文章 0 订阅

气象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展示结果如下:

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
wgrib2是一个用于处理GRIB格式数据的软件。GRIB(GRIdded Binary)是一种常见的气象和气候数据格式。wgrib2可以用来提取、解码和转换GRIB数据。 等距离(等值)和等经纬度是两种不同的数据处理方式。 对于等距离数据,每个格点的距离在水平方向上是相等的。这意味着每个格点之间的间隔是相同的,无论其在地球上的位置如何。因此,等距离数据是基于等距离网格的数据,适用于采用等距离坐标系统的地理区域。 而等经纬度数据则是基于地球的经纬度坐标系统的数据。经度表示从东到西的位置,而纬度表示从南到北的位置。等经纬度数据的每个格点在垂直和水平方向上都有不同的间隔,这是由于地球的形状和尺寸的变化所导致的。 将wgrib2进行等距离转换为等经纬度可以通过一些工具和技术来实现。例如,可以使用编程语言中的相应库或软件,如Python中的pygrib库、NCL(The NCAR Command Language)或者CDO(Climate Data Operators)等进行转换。在转换过程中,必须考虑到源数据的网格定义和分辨率、目标数据的经纬度范围和分辨率等因素,以确保转换后的数据准确符合等经纬度坐标系统。 总之,wgrib2是处理GRIB格式数据的工具,能够提取、解码和转换这些数据。等距离和等经纬度是不同的数据处理方式。将wgrib2中的等距离数据转换为等经纬度数据需要使用适当的工具和技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值