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++;
                }
          }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM