zoukankan      html  css  js  c++  java
  • java 读取气象专业格式NetCDF文件

    一、NetCDF简介
    NetCDF全称为network Common Data Format( “网络通用数据格式”),是一个软件库与机器无关的数据格式,支持创建,访问基于数组的科研数据。分别提供了对Java和C / C++ / Fortran语言。 对程序员来说,它和zip、jpeg、bmp文件格式类似,都是一种文件格式的标准。netcdf文件开始的目的是用于存储气象科学中的数据,现在已经成为许多数据采集软件的生成文件的格式。
    从数学上来说,netcdf存储的数据就是一个多自变量的单值函数。用公式来说就是f(x,y,z,…)=value, 函数的自变量x,y,z等在netcdf中叫做维(dimension)或坐标轴(axix),函数值value在netcdf中叫做变量(Variables)。而自变量和函数值在物理学上的一些性质,比如计量单位(量纲)、物理学名称在netcdf中就叫属性(Attributes)。

    二、需要用到的netcdf的jar

    下载地址:https://www.unidata.ucar.edu/

    本文使用版本:netcdfAll-4.6.14.jar

    需要java 的jdk 8以上版本

    三、读取和打印经纬度变量,了解数据组织结构

        public static void main(String[] args) {
         
            String filename = "pres_temp_4D.nc";
            NetcdfFile dataFile = null;
            try {
              dataFile = NetcdfFile.open(filename, null);
              // Get the latitude and longitude Variables.
              Variable latVar = dataFile.findVariable("latitude");
              Variable lonVar = dataFile.findVariable("longitude");

    System.out.println(NCdumpW.printVariableData(latVar, null)); System.out.println(NCdumpW.printVariableData(lonVar, null)); ArrayFloat.D1 latArray; ArrayFloat.D1 lonArray; latArray = (ArrayFloat.D1) latVar.read(); lonArray = (ArrayFloat.D1) lonVar.read(); System.out.println(NCdumpW.printArray(latArray, "lat", null)); System.out.println(NCdumpW.printArray(lonArray, "lon", null)); // The file is closed no matter what by putting inside a try/catch block. } catch (java.io.IOException e) { e.printStackTrace(); return; } catch (InvalidRangeException e) { e.printStackTrace(); return; } finally { if (dataFile != null) try { dataFile.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } System.out.println("*** SUCCESS reading example file " + filename); }
    NC数据格式:经度:从左到右(正走),纬度:从下到上(正走)
    .read():是读取这个变量所有的数据。
    四、读取所有格点数据实例
    @Override
        public Map<String,Object> getNCDataFromFlex(String searchDate,String elementName,String levelType)
        {
            DecimalFormat decimalFormat=new DecimalFormat(".00");//构造方法的字符格式这里如果小数不足2位,会以0补足
            //接口需求:经度:从左到右(正走),纬度:从上到下(负走)
            //NC数据格式:经度:从左到右(正走),纬度:从下到上(正走)
            String flex_nc_dir=ConfigManager.getInstance().GetProperty("flex_nc_dir");
            Map<String, Object> item = new HashMap<String, Object>();
            int rows=73;
            int cols=73;
            item.put("cols", rows);
            item.put("rows", cols);
            item.put("startLon",113.35373);//sart到end,是小到大
            item.put("startLat",37.99601);//sart到end,是大到小
            item.put("endLon",115.84625);
            item.put("endLat",36);
            item.put("stepLon",0.034);//0.034
            item.put("stepLat",-0.027);
            item.put("missValue",0);
            String filePath="";
            float [][] uArray = new float[rows][cols];
            float [][] vArray = new float[rows][cols];
    
    
            //NC数据格式:经度:从左到右(正走),纬度:从下到上(正走)
            NetcdfFile dataFile = null;
            try {
    
                String dateStr="";
                Date times=DateUtil.strToDate(searchDate,"yyyyMMddHHmmss");
                int hour=times.getHours();
                if(hour>=6)//早上6点以后就用当天的结果
                {
                    hour=hour+1;
                    dateStr=DateUtil.dateToStr(times,"yyyyMMddHHmmss").substring(0,8);
                }
                filePath=flex_nc_dir+dateStr+"/"+dateStr+".nc";
                log.info(filePath);
                dataFile = NetcdfFile.open(filePath, null);
    
                int[] origin = new int[]{hour, 0, 0};//开始位置:时间,经度,纬度
                int[] size = new int[]{1, rows, cols};//数据大小:时间,经度,纬度
    
                //输出UV
                Variable u_Var = dataFile.findVariable("U10");
                Variable v_Var = dataFile.findVariable("V10");
    
                float[] u_Array=(float[])  u_Var.read(origin, size).copyTo1DJavaArray();
                float[] v_Array=(float[])  v_Var.read(origin, size).copyTo1DJavaArray();
    
                for(int i = 0 ; i < rows; i=i+1)
                {
                    for(int j = 0; j< cols; j = j+1 )
                    {
                        uArray[rows-i-1][j] = Float.parseFloat(decimalFormat.format(u_Array[i *cols +j]));
                        vArray[i][j] = Float.parseFloat(decimalFormat.format(v_Array[i *cols +j]));
                    }
                }
    
            } catch (java.io.IOException e) {
                e.printStackTrace();
                return null;
    
            } catch (InvalidRangeException e) {
                e.printStackTrace();
                return null;
    
            }finally {
                if (dataFile != null)
                    try {
                        dataFile.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
            }
            item.put("uArrays",uArray);
            item.put("vArrays",vArray);
            return item;
        }
    read(origin, size):是根据开始位置origin开始读取,然后读取size数据量的数据出来。
    .copyTo1DJavaArray():是将多维变量转换成一维数组。

    五、根据点位所在的经纬度,读取该位置的变量值

    @Override
        public Map<String,Object> getNCFactorFromFlex(String searchDate,float lon,float lat)
        {
            DecimalFormat decimalFormat=new DecimalFormat(".00");//构造方法的字符格式这里如果小数不足2位,会以0补足
            //接口需求:经度:从左到右(正走),纬度:从上到下(负走)
            //NC数据格式:经度:从左到右(正走),纬度:从下到上(正走)
            String flex_nc_dir=ConfigManager.getInstance().GetProperty("flex_nc_dir");
            int rows=73;
            int cols=73;
            String filePath="";
    
            float u_value=0;
            float v_value=0;
            float p_value=0;
            float rh_value=0;
    
    
            //NC数据格式:经度:从左到右(正走),纬度:从下到上(正走)
            NetcdfFile dataFile = null;
            try {
    
                String dateStr="";
                Date times=DateUtil.strToDate(searchDate,"yyyyMMddHHmmss");
                int hour=times.getHours();
                if(hour>=6)//早上6点以后就用times当天的结果
                {
                    hour=hour+1;
                    dateStr=DateUtil.dateToStr(times,"yyyyMMddHHmmss").substring(0,8);
                }
                else//上6点前就用times前一天的结果
                {
                    hour=hour+24+1;
                    dateStr=DateUtil.dateToStr(DateUtil.dateAdd(times,"d",-1),"yyyyMMddHHmmss").substring(0,8);
                }
                filePath=flex_nc_dir+dateStr+"/"+dateStr+".nc";
                log.info("getNCFactorFromFlex"+filePath);
    
                dataFile = NetcdfFile.open(filePath, null);
    
                //00开始,读取第一个网格,用于计算经度序号,纬度序号
                int[] origin0 = new int[]{0, 0, 0};//开始位置:时间序号,经度序号,纬度序号
                int[] size0 = new int[]{1, 73, 73};//数据大小:时间,经度,纬度
    
                Variable x_Var = dataFile.findVariable("XLONG");
                Variable y_Var = dataFile.findVariable("XLAT");
                float[] x_Array=(float[])  x_Var.read(origin0, size0).copyTo1DJavaArray();
                float[] y_Array=(float[])  y_Var.read(origin0, size0).copyTo1DJavaArray();
    
                int x_xh=getLonXHfromNetcdf(x_Array,lon);
                int y_xh=getLatXHfromNetcdf(y_Array,lat);
    
    
                int[] origin = new int[]{hour, x_xh, y_xh};//开始位置:时间序号,经度序号,纬度序号
                int[] size = new int[]{1, 1, 1};//数据大小:时间,经度,纬度
    
                Variable u_Var = dataFile.findVariable("U10");
                Variable v_Var = dataFile.findVariable("V10");
                Variable p_Var = dataFile.findVariable("PSFC");
                Variable rh_Var = dataFile.findVariable("rh2");
    
                float[] u_Array=(float[])  u_Var.read(origin, size).copyTo1DJavaArray();
                float[] v_Array=(float[])  v_Var.read(origin, size).copyTo1DJavaArray();
                float[] p_Array=(float[])  p_Var.read(origin, size).copyTo1DJavaArray();
                float[] rh_Array=(float[])  rh_Var.read(origin, size).copyTo1DJavaArray();
    
                u_value=u_Array[0];
                v_value=v_Array[0];
                p_value=p_Array[0];
                rh_value=rh_Array[0];
    
    
            } catch (java.io.IOException e) {
                e.printStackTrace();
            } catch (InvalidRangeException e) {
                e.printStackTrace();
            }finally {
                if (dataFile != null)
                    try {
                        dataFile.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
            }
            Map<String, Object> item=ClearCalUtil.getWindSpeed(u_value,v_value);
            item.put("u_value",Numberdf.format(u_value));
            item.put("v_value",Numberdf.format(v_value));
            item.put("p_value",Math.round(p_value/100));
            item.put("rh_value",Math.round(rh_value));
            return item;
        }
        public int getLonXHfromNetcdf(float[] x_arr,float lon)
        {
            //纬度数据,列:从前到后,变大;行:从前到后,不变,所以只需要遍历第1行的所有列即可
            int lon_xh=0;
            int rows=73;
            int cols=73;
            for(int i = 0; i< 1; i = i+1 )
            {
                for(int j = 0; j< cols; j = j+1 )
                {
                    float temp=x_arr[i *cols+j];
                    if(temp>lon)
                    {
                        lon_xh=j;
                        return lon_xh;
                    }
                }
            }
    
            return lon_xh;
        }
        public int getLatXHfromNetcdf(float[] y_arr,float lat)
        {
            //纬度数据,列:从前到后,不变;行:从前到后,变大,所以只需要遍历第1列的所有行即可
            int lat_xh=0;
            int rows=73;
            int cols=73;
            for(int i = 0; i< rows; i = i+1 )
            {
                for(int j = 0; j< 1; j = j+1 )
                {
                    float temp=y_arr[i *cols+j];
                    if(temp>lat)
                    {
                        lat_xh=i;
                        return lat_xh;
                    }
                }
            }
    
            return lat_xh;
        }

    其他读取方法

       // read 3D array for that index
                ArrayFloat.D3 presArray, tempArray;
    
                presArray = (ArrayFloat.D3) (presVar.read(origin, shape).reduce());
                tempArray = (ArrayFloat.D3) (tempVar.read(origin, shape).reduce());
              
    
                // now checking the value
                int count = 0;
                for (int lvl = 0; lvl < NLVL; lvl++)
                  for (int lat = 0; lat < NLAT; lat++)
                    for (int lon = 0; lon < NLON; lon++) {
                      if ((presArray.get(lvl, lat, lon) != SAMPLE_PRESSURE + count) ||
                              (tempArray.get(lvl, lat, lon) != SAMPLE_TEMP + count))
                        System.err.println("ERROR incorrect value in variable pressure or temperature");
                      count++;
                    }
              }
  • 相关阅读:
    MyBatis Generator去掉生成的注解
    IDEA git修改远程仓库地址
    Spring Boot 集成druid
    解决 SpringBoot 没有主清单属性
    Intellij IDEA 安装lombok及使用详解
    SET FOREIGN_KEY_CHECKS=0;在Mysql中取消外键约束
    @SpringBootApplication
    IDEA 创建git 分支 拉取分支
    Intellij Idea 将java项目打包成jar
    Spring Could Stream 基本用法
  • 原文地址:https://www.cnblogs.com/tiandi/p/13090051.html
Copyright © 2011-2022 走看看