Last active
March 30, 2023 23:43
-
-
Save bennyistanto/a9dd090698328ee371eb37f9f836fc2f to your computer and use it in GitHub Desktop.
Global TerraClimate's SPEI-based drought indicators blend
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
NAME | |
spei_monthly_blend.py | |
Global TerraClimate's SPEI-based dry/wet indicators blend. | |
DESCRIPTION | |
Input data for this script will use TerraClimate SPEI monthly data in GeoTIFF format | |
This experimental SPEI blends integrate several SPEI scales into a single product. | |
The combines 3-, 6-, 9-, 12-, and 24-month SPEI to estimate the overall dry/wet conditions. | |
METHOD | |
The SPEI values are weighted according to a normalized portion of the inverse of their | |
contributing periods. For example, a 3-month SPEI is weighted to 0.453 of the toral SPEI blend. | |
To calculate the SPEI blend weighting factor, can follow below procedure: | |
1. Sum the total number of contributing months (GOST runs a 3-, 6-, 9-, 12-, and 24-months | |
SPEI for a total of 54-months) | |
2. Divide the total contributing months by the SPEI analysis period (for a 3-month SPEI, | |
54/3 = 18) | |
3. Divide the fractional contribution by the sum of all of the fractional contributions | |
(ensures that total weights always sum to 1.00) | |
REQUIREMENT | |
ArcGIS must installed before using this script, as it required arcpy module. | |
EXAMPLES | |
C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\arcgispro-py3\\python spei_monthly_blend.py | |
NOTES | |
This script is designed to work with global TerraClimate SPEI-based product. | |
If using other data, some adjustment are required: parsing filename, directory, threshold. | |
All TerraClimate data and products are available at s3://wbgdecinternal-ntl/climate/ | |
CONTACT | |
Benny Istanto | |
Climate Geographer | |
GOST/DECAT/DEC Data Group, The World Bank | |
LICENSE | |
This script is in the public domain, free from copyrights or restrictions. | |
VERSION | |
$Id$ | |
TODO | |
xx | |
""" | |
import os | |
import arcpy | |
from datetime import datetime | |
from arcpy.sa import * | |
# Check out the Spatial Analyst extension | |
arcpy.CheckOutExtension("spatial") | |
# To avoid overwriting outputs, change overwriteOutput option to False. | |
arcpy.env.overwriteOutput = True | |
# Set the input folders | |
folder_spei03 = r"X:\\Temp\\TerraClimate\\SPEI\\spei03" | |
folder_spei06 = r"X:\\Temp\\TerraClimate\\SPEI\\spei06" | |
folder_spei09 = r"X:\\Temp\\TerraClimate\\SPEI\\spei09" | |
folder_spei12 = r"X:\\Temp\\TerraClimate\\SPEI\\spei12" | |
folder_spei24 = r"X:\\Temp\\TerraClimate\\SPEI\\spei24" | |
folder_temp = r"X:\\Temp\\TerraClimate\\SPEI\\temp" | |
# Set the output folder | |
folder_blend = r"X:\\Temp\\TerraClimate\\SPEI\\spei_blend_03to24" | |
def spei_blend(folder_spei03, folder_spei06, folder_spei09, folder_spei12, folder_spei24, folder_blend): | |
# Loop through the files in the input folder | |
for raster in os.listdir(folder_spei03): | |
# Check if the file is a TIFF file | |
if raster.endswith(".tif") or raster.endswith(".tiff"): | |
# Get the year, month, and day or day of year from the raster name | |
# wld_cli_terraclimate_spei03_19810301.tif | |
if "_" in raster: | |
year = int(raster[28:32]) | |
month = int(raster[32:34]) | |
day = int(raster[34:36]) | |
date = datetime(year, month, day) | |
# Construct the corresponding filenames in the stats folder | |
raster_suffixes = ["spei03", "spei06", "spei09", "spei12", "spei24"] | |
rasters = [os.path.join(eval("folder_" + suffix), "wld_cli_terraclimate_" + suffix + "_" + date.strftime("%Y%m%d") + ".tif") for suffix in raster_suffixes] | |
# Create a dictionary of folder and raster pairs | |
raster_folders = {"spei03": folder_spei03, "spei06": folder_spei06, "spei09": folder_spei09, "spei12": folder_spei12, "spei24": folder_spei24} | |
# Iterate over the dictionary and check if each raster exists in its corresponding folder | |
for folder, rasters_folder in raster_folders.items(): | |
for raster in rasters: | |
try: | |
if not arcpy.Exists(os.path.join(rasters_folder, raster)): | |
print("Error: {} not found in {}".format(raster, rasters_folder)) | |
raise Exception("Input raster missing") | |
except Exception: | |
continue | |
# Prepare the input | |
try: | |
raster_spei03 = arcpy.Raster(os.path.join(folder_spei03, rasters[0])) | |
raster_spei06 = arcpy.Raster(os.path.join(folder_spei06, rasters[1])) | |
raster_spei09 = arcpy.Raster(os.path.join(folder_spei09, rasters[2])) | |
raster_spei12 = arcpy.Raster(os.path.join(folder_spei12, rasters[3])) | |
raster_spei24 = arcpy.Raster(os.path.join(folder_spei24, rasters[4])) | |
except Exception: | |
continue | |
# Apply the weight on each raster and create virtual raster objects | |
spei03_weighted = arcpy.sa.Times(raster_spei03, 0.453) | |
spei03_virtual = arcpy.sa.Raster(spei03_weighted) | |
spei06_weighted = arcpy.sa.Times(raster_spei06, 0.226) | |
spei06_virtual = arcpy.sa.Raster(spei06_weighted) | |
spei09_weighted = arcpy.sa.Times(raster_spei09, 0.151) | |
spei09_virtual = arcpy.sa.Raster(spei09_weighted) | |
spei12_weighted = arcpy.sa.Times(raster_spei12, 0.113) | |
spei12_virtual = arcpy.sa.Raster(spei12_weighted) | |
spei24_weighted = arcpy.sa.Times(raster_spei24, 0.057) | |
spei24_virtual = arcpy.sa.Raster(spei24_weighted) | |
# Calculate the sum of the weighted rasters | |
output_speiblend = os.path.join(folder_blend, "wld_cli_terraclimate_speiblend_03to24_" + date.strftime("%Y%m%d") + ".tif") | |
speiblend = arcpy.sa.CellStatistics([spei03_virtual,spei06_virtual,spei09_virtual,spei12_virtual,spei24_virtual], "SUM", "DATA") | |
speiblend.save(output_speiblend) | |
print(output_speiblend + " completed") | |
# Check out the Spatial Analyst extension | |
arcpy.CheckInExtension("spatial") | |
# Main function | |
def main(): | |
# Call the spei_blend() function for the input folder | |
spei_blend(folder_spei03, folder_spei06, folder_spei09, folder_spei12, folder_spei24, folder_blend) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment