R語言讀取大型NetCDF文件

失蹤人口迴歸,本篇來介紹下R語言讀取大型NetCDF文件的一些實踐。

1 NetCDF數據簡介

先給一段Wiki上關於NetCDF的定義。

NetCDF (Network Common Data Form) is a set of software libraries and self-describing, machine-independent data formats that support the creation, access, and sharing of array-oriented scientific data. The project homepage is hosted by the Unidata program at the University Corporation for Atmospheric Research (UCAR). They are also the chief source of netCDF software, standards development, updates, etc. The format is an open standard. NetCDF Classic and 64-bit Offset Format are an international standard of the Open Geospatial Consortium.

The project started in 1988 and is still actively supported by UCAR. The original netCDF binary format (released in 1990, now known as "netCDF classic format") is still widely used across the world and continues to be fully supported in all netCDF releases. Version 4.0 (released in 2008) allowed the use of the HDF5 data file format. Version 4.1 (2010) added support for C and Fortran client access to specified subsets of remote data via OPeNDAP. Version 4.3.0 (2012) added a CMake build system for Windows builds. Version 4.7.0 (2019) added support for reading Amazon S3 objects. Further releases are planned to improve performance, add features, and fix bugs.

本質上NetCDF是一個多維矩陣的數據,常用於地球科學領域的數據存儲。

wiki百科定義

給出一個典型的例子(CHAP的O3數據)。

2 R語言處理大型NetCDF文件

我們可以看到NetCDF本質上這就是多個柵格疊在一起的文件,在R裏面的處理方式基本依賴於幾個柵格和NetCDF相關的包。包括ncdf4, raster/terra。

install.packages('ncdf4')
install.packages('raster')
install.packages('terra')

接下來給出一個標準的讀nc文件的代碼。

#讀取文件
nc_o3 <- nc_open('CHAP_O3_Y10K_2013_V1.nc')

#顯示文件內容
print(nc_o3)

#獲取經緯度,變量名與缺失值
long <- ncvar_get(nc_o3, 'lon')
lat <- ncvar_get(nc_o3, 'lat')
o3 <- ncvar_get(nc_o3, 'O3')
fillvalue <- ncatt_get(nc_o3, "O3", "fill_value")
o3[o3==fillvalue$value] <- NA

#生成柵格
r <- raster(t(o3), xmn=min(long), xmx=max(long), ymn=min(lat), ymx=max(lat), 
            crs=CRS("+proj=longlat +datum=WGS84 +no_defs"))

#繪圖
plot(r)

這部分代碼的運行結果就是第一部分顯示的那張圖。這裏要注意的是,print(nc_o3)那句代碼是會決定下面獲取經緯度,變量名與缺失名的關鍵。如圖所示,這裏的變量數量是一個,就是臭氧濃度O3,單位是$\mu g/m^3$,變量名叫o3,缺失值爲-999,然後對應的經緯度名字是lat和lon。

由於這個數據是10 km的處理起來比較快。當遇到全球或者全國比較精細化的NetCDF文件的時候,讀取和另存爲柵格可能會非常耗內存,因爲R語言在處理數據的時候,默認是把數據全部讀進去內存。筆者最近處理了一個全國km級的逐月氣象數據。當我加載某一個三年的數據時,忽然內存飆升了,存進去的多維矩陣能佔據5.7G內存。因此這就對處理速度和機子要求很高,也會有很多麻煩。那麼當然我並不需要全國的數據,實際上我也是裁出研究區的數據。因此做了一下搜索和實踐,總結了下如何根據需求,只讀取部分區域的大型NetCDF文件。這樣子就不需要機子內存的高要求了,這裏以福建省爲例(福建省的shp數據可以參照如下的鏈接下載)。使用的NetCDF數據爲國家青藏高原科學數據中心1901到2022年逐月1km降水數據。

福建省標準地圖矢量數據首次公開發布

中國1km分辨率逐月降水量數據集(1901-2022)

中國1km分辨率逐月平均氣溫數據集(1901-2022)

主要的代碼如下:

#install.packages('sf')
#install.packages('raster')
#install.packages('terra')
#install.packages('ncdf4')
#install.packages('rasterVis')
#Load library
library(sf)
library(ncdf4)
library(raster)
library(terra)
library(rasterVis)

#Read shapefile
fjcities <- read_sf('city.shp')
fjcitieswgs <- st_transform(fjcities, crs = '+proj=longlat +datum=WGS84 +no_defs')

#Read netcdf file
nc_pre <- nc_open('pre_2021.nc')

#Display the information of NetCDF
print(nc_pre)

fjcitieswgs

#To obtain the longitude, latitude, time, and name of variable
long <- ncvar_get(nc_pre, 'lon')
lat <- ncvar_get(nc_pre, 'lat')

#Calculate numbers of rows and columns of the specific study area
LonIdx <- which(long[] > 115 & long[] < 121)
LatIdx <- which(lat[] > 23 & lat[] < 29)

pre <- ncvar_get(nc_pre, 'pre', 
                 start = c(LonIdx[1], LatIdx[1],1),
                 count = c(length(LonIdx), length(LatIdx),1))
fillvalue <- ncatt_get(nc_pre, "pre", "missing_value")
pre[pre==fillvalue$value] <- NA

#To generate raster
r <- raster(t(pre), xmn=min(long[LonIdx]), xmx=max(long[LonIdx]), ymn=min(lat[LatIdx]), ymx=max(lat[LatIdx]), 
            crs=CRS("+proj=longlat +datum=WGS84 +no_defs"))

#Display the raster
plot(r)

#Clip the raster using the shapefile
r <- crop(r, fjcitieswgs)
r <- mask(r, fjcitieswgs)

#Display the raster
plot(r)

#Using different r package to plot raster
levelplot(r)

關鍵在於ncvar_get函數裏的start和count參數。這兩個負責控制讀取NC的行列數據以及多維數(如果沒有時間軸,直接給一個2個元素的數組就行)。start是讀取NetCDF的起始行列數,count是讀取NetCDF的數量。後續轉柵格的操作是raster函數的寫法。由於raster快停止維護了。我們也會提供terra包的寫法(實際上差別不大)。

#Use terra pacakge to generate raster
rn <- rast(t(pre), crs= '+proj=longlat +datum=WGS84 +no_defs')

#Display the raster
plot(rn)

由於後續的裁剪代碼terra和raster毫無差別。這裏就不贅述了。這部分代碼我也會放在我的Github項目上(My Studies of Urban GIS)。

最後感謝下Google搜到的幾個資料。

參考鏈接:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章