[MODIS数据处理#8]批量将ET栅格的时间分辨率从8-day转换为monthly的一种思路


系列文章目录: MODIS数据处理


一、问题描述

以EarthData提供的MOD16A2数据集(8-day,500m)为基础得到逐月的蒸散量(ET)栅格影像。该数据集的数据编号对应的日序如下图所示。以平年为例,3月份被包含在057、065、073、081、089这五幅影像中。
在这里插入图片描述
在之前的文章中,我提供了一种简单的思路利用重镶嵌功能,将ET栅格的时间分辨率从8-day转换为monthly,详情可参考[MODIS数据处理#5]例二:将ET栅格的时间分辨率从8-day转换为monthly
本文在此基础上提供了一种批量处理的处理流程,希望能对各位有所帮助。


二、数据预处理

1、下载数据

下载MOD16A2数据集,详细操作可参考:MOD16A2数据集下载教程
这里下载了2000~2019年h25v04、h25v05、h26v04、h26v05、h27v05五个区块的MOD16A2数据(.hdf),如下:
在这里插入图片描述
在这里插入图片描述

2、提取子数据集、镶嵌、重投影

这一步可以用MRT或HEG工具的批处理方法完成,可参考:
利用MRT工具预处理MODIS数据
或者基于ArcGIS的自定义脚本分步完成,可参考:
【ArcGIS自定义脚本工具】批量提取子数据集
【ArcGIS自定义脚本工具】按区块批量镶嵌MODIS影像
【ArcGIS自定义脚本工具】批量重投影栅格脚本
也可以利用LAADS DAAC(https://ladsweb.modaps.eosdis.nasa.gov/search/)的在线处理功能对HDF文件进行提取、拼接、投影等操作。
在这里插入图片描述

3、裁剪

按选定的矢量边界文件对ET栅格进行裁剪,这里以黄土高原为例,具体步骤可以参考:
【ArcGIS自定义脚本工具】批量裁剪栅格脚本
裁剪后得到的文件如下所示:
在这里插入图片描述
在这里插入图片描述

4、排除特殊值区域

由于MOD16数据集对于城市、冻土冰雪、裸地、水体这些区域仅用特殊值标记,不计算ET值,在此对这些区域进行排除。所用到的工具是设为空函数。具体的操作步骤可以参考:
批量设为空函数脚本
在这里插入图片描述

三、按月镶嵌至新栅格

1、批量按月镶嵌脚本

1.1、功能介绍

将包含X月初至X月末时间长度的8-day分辨率的ET影像利用镶嵌至新栅格工具合成到月分辨率。但需要注意以下两点:

  • 平闰年的情况有所差异
  • 平年的最后一景影像(第361天)的数据代表的不是8天的ET和,而是5天(361 ~365)的ET总和。同理,闰年的最后一景影像是6天(361 ~366)的ET总和。

在这里插入图片描述
为了方便批处理,在合成1~11月的影像时,镶嵌运算符选择MEAN;在合成12月的影响时,镶嵌运算符选择SUM。这两个镶嵌运算符的说明见下图:
在这里插入图片描述

1.2、脚本代码

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
import time
import arcpy


def show_files(path, out_files, suffix=".tif", out_type="path"):
    file_list = os.listdir(path)
    for file in file_list:
        cur_path = os.path.join(path, file)
        if os.path.isdir(cur_path):
            show_files(cur_path, out_files, out_type=out_type)
        else:
            if file.endswith(suffix):
                if out_type == "path":
                    out_files.append(cur_path)
                elif out_type == "name":
                    out_files.append(file)
                else:
                    raise Exception("please select correct out_type value:path ;name")


months_ping = {1: [1, 9, 17, 25],
               2: [25, 33, 41, 49, 57],
               3: [57, 65, 73, 81, 89],
               4: [89, 97, 105, 113],
               5: [121, 129, 137, 145],
               6: [145, 153, 161, 169, 177],
               7: [177, 185, 193, 201, 209],
               8: [209, 217, 225, 233, 241],
               9: [241, 249, 257, 265, 273],
               10: [273, 281, 289, 297],
               11: [305, 313, 321, 329],
               12: [329, 337, 345, 353, 361]}
months_run = {1: [1, 9, 17, 25],
              2: [25, 33, 41, 49, 57],
              3: [57, 65, 73, 81, 89],
              4: [89, 97, 105, 113, 121],
              5: [121, 129, 137, 145],
              6: [153, 161, 169, 177],
              7: [177, 185, 193, 201, 209],
              8: [209, 217, 225, 233, 241],
              9: [241, 249, 257, 265, 273],
              10: [273, 281, 289, 297, 305],
              11: [305, 313, 321, 329],
              12: [329, 337, 345, 353, 361]}

in_path = arcpy.GetParameterAsText(0)  # r"H:\taobao\suisdio\loess"
out_path = arcpy.GetParameterAsText(1)
pixel_type = arcpy.GetParameterAsText(2)
colormap_mode = arcpy.GetParameterAsText(3)

arcpy.env.workspace = in_path
all_tifs = []
show_files(in_path, all_tifs, out_type="name")
name_map = {}
avail_years = []
for fname in all_tifs:
    y = int(fname.split(".")[1][1:5])
    d = int(fname.split(".")[1][-3:])
    keyname = "{0}.{1}".format(y, d)
    name_map[keyname] = fname
    if y not in avail_years:
        avail_years.append(y)

base = all_tifs[0]
out_coor_system = arcpy.Describe(base).spatialReference
cell_width = arcpy.Describe(base).meanCellWidth
band_count = arcpy.Describe(base).bandCount

groups = {}
for year in avail_years:
    months_temp = months_ping
    if year % 4 == 0:
        months_temp = months_run
    for month in months_temp.keys():
        new_name = "A{0}M{1}.tif".format(year, month)
        target_days = months_temp[month]
        groups[new_name] = []
        for i in target_days:
            fkey = "{0}.{1}".format(year, i)
            if fkey in name_map:
                groups[new_name].append(name_map[fkey])

nums = len(groups)
num = 1
for i in groups:
    s = time.time()
    month = int(i.split(".")[0][6:])  # A2000M2.tif
    if len(groups[i]) == 0:
        arcpy.AddMessage("{0}/{1} | {2} is None".format(num, nums, i))
        num = num + 1
        continue
    groups[i] = ';'.join(groups[i])
    if not os.path.exists(os.path.join(out_path, i)):
        if month != 12:
            arcpy.MosaicToNewRaster_management(groups[i], out_path, i, out_coor_system, pixel_type, cell_width, band_count,
                                               "MEAN", colormap_mode)
        else:
            arcpy.MosaicToNewRaster_management(groups[i], out_path, i, out_coor_system, pixel_type, cell_width, band_count,
                                               "SUM", colormap_mode)
        e = time.time()
        arcpy.AddMessage("{0}/{1} | {2} Completed, time used {3}s".format(num, nums, i, e - s))
    else:
        e = time.time()
        arcpy.AddMessage("{0}/{1} | {2} existed, , time used {3}s".format(num, nums, i, e - s))
    num = num + 1

注意:
上述代码中对栅格文件的命名有要求,栅格命名必须满足"xxxxx.AYYYYDDD.xxxxx"的形式,即以 . 为分隔符对文件名进行分组后,第二组满足形式AYYYYDDD,其中YYYY为年份,DDD为日序,例如A2000117。脚本从栅格的文件名中获取该栅格对应的年份和日序,可通过修改下面的代码块解决。

for fname in all_tifs:
    y = int(fname.split(".")[1][1:5]) # 年份在文件名中的位置
    d = int(fname.split(".")[1][-3:]) # 日序在文件名中的位置
    keyname = "{0}.{1}".format(y, d)
    name_map[keyname] = fname
    if y not in avail_years:
        avail_years.append(y)

1.3、工具参数

在这里插入图片描述

1.4、运行界面

在这里插入图片描述

2、批量单位换算脚本

2.1、功能介绍

经过上一步的操作,已经初步得到了月分辨率的ET栅格影像,对于1~11月份来说,此时的单位为mm/8day,缩放因子为0.1。以下图为例,黄土高原地区2000年1月份的ET范围为2.375mm/8day至9.5mm/8day。
在这里插入图片描述
而经过上一步脚本的操作后,由于对于12月份采用的镶嵌运算符为SUM,故此时的单位及缩放因子为:

  • 平年,mm/37day,缩放因子为0.1
  • 闰年,mm/38day,缩放因子为0.1

以下图为例,黄土高原地区2000年12月份的ET范围为0mm/38day至47.4mm/38day。
在这里插入图片描述
因此,为了方便对比,利用工具,将单位统一换算为mm/day。

2.2、脚本代码

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import arcpy
from arcpy import env
from arcpy.sa import *
import os

raster_path = arcpy.GetParameterAsText(0)
new_dir_name = arcpy.GetParameterAsText(1)


def multiply_batch(new_dir_name, new_prefix="united_"):
    env.workspace = raster_path
    raster_list = arcpy.ListRasters()
    for inraster in raster_list:
        year = int(inraster.split(".")[0][1:5]) # 年份在文件名中的位置
        month = int(inraster.split(".")[0][6:]) # 日序在文件名中的位置
        if month == 12:
            if year % 4 == 0:
                scale_factor = 0.1 / 38
            else:
                scale_factor = 0.1 / 37
        else:
            scale_factor = 0.1 / 8
        outraster = "\\" + new_dir_name + "\\" + new_prefix + inraster
        arcpy.gp.Times_sa(inraster, scale_factor, outraster)
        arcpy.AddMessage("Step2:" + str(new_prefix) + inraster[:] + "  has done.")
        arcpy.SetProgressorPosition()
    arcpy.AddMessage("Step2:Completed")


arcpy.ResetProgressor()

dir_name = new_dir_name
out_path = raster_path + "\\" + dir_name
os.makedirs(out_path)
arcpy.AddMessage("Step1:Creating new folder named " + str(dir_name))
arcpy.AddMessage("Step1:Completed")
if arcpy.CheckExtension("Spatial") == "Available":
    multiply_batch(dir_name)
else:
    arcpy.AddMessage("Error!!! Spatial Analyst is unavailable")

2.3、工具参数

在这里插入图片描述

2.4、运行界面

在这里插入图片描述


四、结果与讨论

1、结果

在这里插入图片描述
在这里插入图片描述

2、讨论

  • 按月镶嵌栅格时输入栅格的选择不够严谨
    例一: 将四张8天合成的影像(001;009;017;025),利用镶嵌至新栅格到一张上,代表一月的数据。
    在这里插入图片描述
    例二: 在合成九月份ET影像的过程中,273中属于9月份的只有9月30日一天。那么将五张8天合成的影像(241;249;257;265;273),利用镶嵌至新栅格到一张上,代表九月数据。
    在这里插入图片描述
    上述的两个例子中的合成方式是合理的吗?例一中,合成一月份ET时编号025的影像对应1月25日 ~ 2月1日的数据。而例二中,合成九月份ET时编号273的影像对应9月30日 ~ 10月7日的数据。这种做法 并不严谨

  • 35
    点赞
  • 195
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 37
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Salierib

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值