如何在 R 中根据每小时 NetCDF 数据创建每月系列?

问题描述 投票:0回答:1

我正在研究存储在 NetCDF 文件中的 NEE(网络生态系统交换数据),我将其称为 NEE_2022.nc 。该文件在我的 wd 中。 空间覆盖整个欧洲,分辨率约为1公里;时间范围为 2022 年,时间分辨率为每小时。 在这里我提供一些有关数据的更多信息:

**1 variables** (excluding dimension variables):
        float NEE[lon,lat,time]   
            long_name: net ecosystem exchange
            units: micromoles/m2/s
            _FillValue: 1.00000001504747e+30
            missing_value: 1.00000001504747e+30
**3 dimensions**:
        time  Size:8760   *** is unlimited *** 
            standard_name: time
            long_name: time endpoint
            units: hours since 2022-01-01 00:00:00
            calendar: standard
            axis: T
        lon  Size:400 
            standard_name: longitude
            long_name: longitude
            units: degrees_east
            axis: X
        lat  Size:480 
            standard_name: latitude
            long_name: latitude
            units: degrees_north
            axis: Y

这是我的目标: 我想每月对每个像素进行平均; 我还想为每个月 NEE 栅格创建一张地图。 不需要空间子集。

注意 R.version 命令返回以下文本:

platform       x86_64-w64-mingw32               
arch           x86_64                           
os             mingw32                          
crt            ucrt                             
system         x86_64, mingw32                  
status                                          
major          4                                
minor          2.2                              
year           2022                             
month          10                               
day            31                               
svn rev        83211                            
language       R                                
version.string R version 4.2.2 (2022-10-31 ucrt)

我在打开文件时遇到问题。 当我运行以下代码时:

library(ncdf4)
library(raster) 
library(rgdal) 
library(ggplot2) 
library(terra)

NEE_2022 <- nc_open('NEE_2022.nc',readunlim=FALSE)
NEE.array <- ncvar_get(NEE_2022, "NEE")

我的记忆力有问题。我收到以下错误消息:

错误:无法分配大小为 12 GB 的向量

然后,我通过使用

ncvar_get()
函数中的“start”和“count”参数成功创建了数组。我尝试只选择第一天(24 小时)。我做了以下事情:

NEE.array <- ncvar_get(NEE_2022, "NEE", start = c(1,1,1), count = c(-1,-1,24))

我该如何继续?

r time-series raster netcdf
1个回答
0
投票

由于 NEE 文件太大,无法装入内存,因此必须将其分段处理。

解决方案1:显而易见的方法

将每小时数据汇总为每日数据是最容易理解的方法,之后您必须将每日数据汇总为每月数据(在您的问题中,您提到“每月平均每个像素”,但我假设您想要总和为“每月 NEE”,而不是平均值为“每月平均每小时 NEE”)。执行此操作的基本循环如下所示:

library(ncdf4)
NEE_2022 <- nc_open('NEE_2022.nc')

# Number of days per month
days_in_month <- c(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

# First hour of every month in 2022
h1 <- c(1, 745, 1417, 2161, 2881, 3625, 4345, 5089, 5809, 6553, 7273, 8017)

# Array for the result
NEE_data <- array(0, dim = c(480, 400, 12))

for (m in 1:12) {
    mon <- array(0, dim = c(480, 400))
    for (d in 1:days_in_month[m]) {
        data <- ncvar_get(NEE_2022, "NEE", 
                          start = c(1, 1, h1[m]), 
                          count = c(-1, -1, 24))
        mon <- mon + rowSums(data, dims = 2) * 3600
    }
    NEE_data[, , m] <- mon
}
nc_close(NEE_2022)

您还可以将两个循环合并为一个,但代价是从文件中读取更大的数据,这可能会耗尽您的内存:

for (m in 1:12) {
    data <- ncvar_get(NEE_2022, "NEE", 
                      start = c(1, 1, h1[m]), 
                      count = c(-1, -1, 24 * days_in_month[m]))
    NEE_data[, , m] <- rowSums(data, dims = 2) * 3600
}

解决方案 2:R 方式

R think中,你应该用向量来构建你的问题,尽可能避免循环。虽然由于文件较大而无法避免循环,但您仍然可以对处理逻辑进行矢量化。在这种情况下,这意味着在 time 维度上创建一个

factor
,然后使用它在一次操作中根据文件大小逐像素提取所有每月总和:

# Create the factor
f <- as.factor(rep(rep(1:12, days_in_month), each = 24))

# Loop through every pixel
for (lat in 1:480) {
    for (lon in 1:400) {
        data <- ncvar_get(NEE_2022, "NEE", start = c(lat, lon, 1), count = c(1, 1, -1))
        NEE_data[lon, lat, ] <- tapply(data, f, sum) * 3600
    }
}

您可以通过读取和处理较大的块来减少循环数,例如10 x 10 纬度/经度块。

潜在的陷阱

上述代码通常应放置在函数内,以便可以轻松存储和重用。问题是上面的代码高度依赖于您正在处理的文件的具体情况。如果您想处理另一个文件并且该数据覆盖地球的另一个区域,则尺寸可能会发生变化。如果您处理 2020 年的数据,则必须考虑闰日。

如果数据文件符合 CF 元数据约定(这很可能),您可以查看

CFtime
,因为它可以自动处理时间序列,并将生成在第二个解决方案中使用的因子.

© www.soinside.com 2019 - 2024. All rights reserved.