Last active
October 10, 2022 14:45
-
-
Save bennyistanto/44b1b8decf6e49cef422b5c8de33edb1 to your computer and use it in GitHub Desktop.
TerraClimate's SPEI drought characteristics
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 | |
extract_spei_dry_month.py | |
DESCRIPTION | |
Input data for this script will use TERRACLIMATE's SPEI-12, generated using pypi climate-indices | |
This script will calculate number of: | |
(i) Dry month, | |
(ii) Total dry month | |
(iii) Consecutive dry month and | |
(iv) Maximum consecutive dry month | |
PROCESS | |
(i) Extract TerraClimate's monthly SPEI-12 with value less than -1.2 (threshold for Moderately Dry), 1958-2021 | |
(ii) If SPEI < -1.2 = Yes, then assign 1 otherwise 0. | |
(iii) For number of consecutive information, it will accumulate to next data calculation result if the value = 1. | |
If not, start from 0 again. | |
(iv) Total dry month derived from each dry month data | |
(v) Number of maximum concecutive months derived from each consecutive dry month data | |
APPLICATION | |
The accumulation value will use to identified the monthly drought duration accumulation, | |
month by month, year by year. | |
REQUIREMENT | |
ArcGIS must installed before using this script, as it required arcpy module. | |
NOTES | |
This script is designed to work with global SPEI data generated from TerraClimate, following this guideline | |
https://gist.github.com/bennyistanto/efd8050f02d5e396900ad7f91b329f82 | |
If using other data, some adjustment are required: parsing filename, directory, threshold | |
CONTACT | |
Benny Istanto | |
- Climate Geographer, GOST/DECAT/DEC Data Group, The World Bank | |
- Department of Geophysics and Meteorology, Bogor Agricultural University, Indonesia | |
LICENSE | |
This script is in the public domain, free from copyrights or restrictions. | |
VERSION | |
$Id$ | |
""" | |
import arcpy | |
from arcpy.sa import * | |
import os, sys, traceback | |
import re | |
from datetime import date | |
from dateutil.relativedelta import relativedelta | |
# To avoid overwriting outputs, change overwriteOutput option to False. | |
arcpy.env.overwriteOutput = True | |
# Check if there is DRY Month data in output folder | |
def create_DM_List(_DM_folder): | |
print("start reading existing DRY Month Dataset....") | |
print("looking for file with naming wld_cli_terraclimate_spei12_dry_YYYYMMDD") | |
DM_Date_List=[] | |
for DM_Data in os.listdir(_DM_folder): | |
if DM_Data.endswith(".tif") or DM_Data.endswith(".tiff"): | |
print("found " + DM_Data + " in the DRY Month folder") | |
parse_String = DM_Data.split('_') | |
DM_Data_Date = parse_String[4] | |
DM_Date_List.append(DM_Data_Date) | |
return DM_Date_List | |
# Check if there is Consecutive DRY Month data in output folder | |
def create_CDM_List(_CDM_folder): | |
print("start reading existing Consecutive DRY Month Dataset....") | |
print("looking for file with naming wld_cli_terraclimate_spei12_dry_YYYYMMDD") | |
CDM_Date_List=[] | |
for CDM_Data in os.listdir(_CDM_folder): | |
if CDM_Data.endswith(".tif") or CDM_Data.endswith(".tiff"): | |
print("found " + CDM_Data + " in the Consecutive DRY Month folder") | |
parse_String = CDM_Data.split('_') | |
CDM_Data_Date = parse_String[4] | |
CDM_Date_List.append(CDM_Data_Date) | |
return CDM_Date_List | |
# Check input data | |
def create_monthly_List(_tif_folder): | |
print("start reading list of monthly SPEI data....") | |
print("looking for file with naming wld_cli_terraclimate_spei12_YYYY-MM-DD") | |
Monthly_Date_List=[] | |
for Monthly_Data in os.listdir(_tif_folder): | |
if Monthly_Data.endswith(".tif") or Monthly_Data.endswith(".tiff"): | |
print("found " + Monthly_Data+ " in the monthly SPEI folder") | |
finds = re.findall(r'[^\d](\d{4}[^\d]\d{2}[^\d]\d{2})([^\d]|$)', Monthly_Data) | |
if not finds: | |
raise Exception('YYYY.MM.DD pattern not found') | |
ymd = re.sub(r'[^\d]+', '', finds[0][0]) | |
Monthly_Data_Date = ymd | |
Monthly_Date_List.append(Monthly_Data_Date) | |
return sorted(Monthly_Date_List) | |
# Execute first Dry condition | |
def execute_first_DM(_tiffolder, _DMFolder, threshold): | |
# Spatial reference WGS-84 | |
sr = arcpy.SpatialReference(4326) | |
print("looking at the first monthly SPEI data in tif folder...") | |
monthly_list = create_monthly_List(_tiffolder) | |
first_date = min(monthly_list) | |
print("execute first SPEI data from date "+first_date) | |
first_data_name = 'wld_cli_terraclimate_spei12_{0}-{1}-{2}.tif'.format(first_date[0:4], first_date[4:6], first_date[6:8]) | |
first_monthly_data = os.path.join(_tiffolder, first_data_name) | |
monthly_Date = date(int(first_date[0:4]), int(first_date[4:6]), int(first_date[6:8])) | |
dry_date = monthly_Date + relativedelta(months=1) | |
print("creating dry data "+str(dry_date)+ " from monthly SPEI data from "+str(monthly_Date)) | |
DMyear = str(dry_date.year) | |
DMmonth = str(dry_date.month) | |
DMday = str(dry_date.day) | |
print(str(dry_date)) | |
DMFilename = 'wld_cli_terraclimate_spei12_dry_{0}{1}{2}.tif'.format(DMyear.zfill(4), DMmonth.zfill(2), DMday.zfill(2)) | |
print("Processing "+DMFilename) | |
arcpy.CheckOutExtension("spatial") | |
outCon = Con(Raster(first_monthly_data) < Float(threshold), 1, 0) | |
outCon.save(os.path.join(_DMFolder, DMFilename)) | |
arcpy.DefineProjection_management(os.path.join(_DMFolder, DMFilename), sr) | |
arcpy.CheckInExtension("spatial") | |
print("file " + DMFilename + " is created") | |
# Execute first Dry condition | |
def execute_first_CDM(_tiffolder, _CDMFolder, threshold): | |
# Spatial reference WGS-84 | |
sr = arcpy.SpatialReference(4326) | |
print("looking at the first monthly SPEI data in tif folder...") | |
monthly_list = create_monthly_List(_tiffolder) | |
first_date = min(monthly_list) | |
print("execute first SPEI data from date "+first_date) | |
first_data_name = 'wld_cli_terraclimate_spei12_{0}-{1}-{2}.tif'.format(first_date[0:4], first_date[4:6], first_date[6:8]) | |
first_monthly_data = os.path.join(_tiffolder, first_data_name) | |
monthly_Date = date(int(first_date[0:4]), int(first_date[4:6]), int(first_date[6:8])) | |
dry_date = monthly_Date + relativedelta(months=1) | |
print("creating dry data "+str(dry_date)+ " from monthly SPEI data from "+str(monthly_Date)) | |
CDMyear = str(dry_date.year) | |
CDMmonth = str(dry_date.month) | |
CDMday = str(dry_date.day) | |
print(str(dry_date)) | |
CDMFilename = 'wld_cli_terraclimate_spei12_dry_{0}{1}{2}.tif'.format(CDMyear.zfill(4), CDMmonth.zfill(2), CDMday.zfill(2)) | |
print("Processing "+CDMFilename) | |
arcpy.CheckOutExtension("spatial") | |
outCon = Con(Raster(first_monthly_data) < Float(threshold), 1, 0) | |
outCon.save(os.path.join(_CDMFolder, CDMFilename)) | |
arcpy.DefineProjection_management(os.path.join(_CDMFolder, CDMFilename), sr) | |
arcpy.CheckInExtension("spatial") | |
print("file " + CDMFilename + " is created") | |
# Execute next DRY Month data | |
def execute_DM(_lastdate, _tiffolder, _DM_folder, threshold): | |
# Spatial reference WGS-84 | |
sr = arcpy.SpatialReference(4326) | |
date_formatted = date(int(_lastdate[0:4]), int(_lastdate[4:6]), int(_lastdate[6:8])) | |
last_dryname = 'wld_cli_terraclimate_spei12_dry_{0}'.format(_lastdate) | |
last_dryfile = os.path.join(_DM_folder, last_dryname) | |
next_monthlyname = 'wld_cli_terraclimate_spei12_{0}-{1}-{2}.tif'.format(_lastdate[0:4], _lastdate[4:6], _lastdate[6:8]) | |
next_monthlydata = os.path.join(_tiffolder, next_monthlyname) | |
if arcpy.Exists(next_monthlydata): | |
print("next monthly data is available...") | |
print("start processing next DRY Month...") | |
new_dry_date = date_formatted + relativedelta(months=1) | |
DMyear1 = str(new_dry_date.year) | |
DMmonth1 = str(new_dry_date.month) | |
DMday1 = str(new_dry_date.day) | |
new_dry_name = 'wld_cli_terraclimate_spei12_dry_{0}{1}{2}.tif'.format(DMyear1.zfill(4), DMmonth1.zfill(2), DMday1.zfill(2)) | |
print("Processing DRY Month from "+last_dryfile+" and "+next_monthlydata) | |
arcpy.CheckOutExtension("spatial") | |
outDMCon = Con(Raster(next_monthlydata) < Float(threshold), 1, 0) | |
outDMCon.save(os.path.join(_DM_folder, new_dry_name)) | |
arcpy.DefineProjection_management(os.path.join(_DM_folder, new_dry_name), sr) | |
arcpy.CheckInExtension("spatial") | |
print("DRY Month File "+new_dry_name+" is created") | |
else: | |
print("next monthly data is not available. Exit...") | |
# Execute next Consecutive DRY Month data | |
def execute_CDM(_lastdate, _tiffolder, _CDM_folder, threshold): | |
# Spatial reference WGS-84 | |
sr = arcpy.SpatialReference(4326) | |
date_formatted = date(int(_lastdate[0:4]), int(_lastdate[4:6]), int(_lastdate[6:8])) | |
last_dryname = 'wld_cli_terraclimate_spei12_dry_{0}'.format(_lastdate) | |
last_dryfile = os.path.join(_CDM_folder, last_dryname) | |
next_monthlyname = 'wld_cli_terraclimate_spei12_{0}-{1}-{2}.tif'.format(_lastdate[0:4], _lastdate[4:6], _lastdate[6:8]) | |
next_monthlydata = os.path.join(_tiffolder, next_monthlyname) | |
if arcpy.Exists(next_monthlydata): | |
print("next monthly data is available...") | |
print("start processing next Consecutive DRY Month...") | |
new_dry_date = date_formatted + relativedelta(months=1) | |
CDMyear1 = str(new_dry_date.year) | |
CDMmonth1 = str(new_dry_date.month) | |
CDMday1 = str(new_dry_date.day) | |
new_dry_name = 'wld_cli_terraclimate_spei12_dry_{0}{1}{2}.tif'.format(CDMyear1.zfill(4), CDMmonth1.zfill(2), CDMday1.zfill(2)) | |
print("Processing Consecutive DRY Month from "+last_dryfile+" and "+next_monthlydata) | |
arcpy.CheckOutExtension("spatial") | |
outCDMCon = Con(Raster(next_monthlydata) < Float(threshold), Raster(last_dryfile)+1, 0) | |
outCDMCon.save(os.path.join(_CDM_folder, new_dry_name)) | |
arcpy.DefineProjection_management(os.path.join(_CDM_folder, new_dry_name), sr) | |
arcpy.CheckInExtension("spatial") | |
print("Consecutive DRY Month File "+new_dry_name+" is created") | |
else: | |
print("next monthly data is not available. Exit...") | |
# Run the script | |
def create_DM(_DM_folder, _tiffolder, threshold): | |
DM_Date_List = create_DM_List(_DM_folder) | |
Monthly_list = create_monthly_List(_tiffolder) | |
# if there is no DRY data, creating new DRY data | |
if len(DM_Date_List)==0: | |
print("No DRY Month data found...") | |
print("Creating first DRY Month data...") | |
execute_first_DM(_tiffolder, _DM_folder, threshold) | |
DM_Date_List = create_DM_List(_DM_folder) | |
# if there is DRY Month data | |
print("DRY Month data found. Looking for latest DRY Month data...") | |
#Check last DRY Month available | |
last_date = max(DM_Date_List) | |
#Check last monthly data availabke | |
max_monthly_date = max(Monthly_list) | |
last_DM_date = date(int(last_date[0:4]), int(last_date[4:6]), int(last_date[6:8])) | |
last_monthly_date = date(int(max_monthly_date[0:4]), int(max_monthly_date[4:6]), int(max_monthly_date[6:8])) | |
# process DRY Month to every monthly data available after last DRY Month data | |
while last_monthly_date + relativedelta(months=1) > last_DM_date: | |
execute_DM(last_date, _tiffolder, _DM_folder, threshold) | |
last_DM_date=last_DM_date+relativedelta(months=1) | |
DMyear2 = str(last_DM_date.year) | |
DMmonth2 = str(last_DM_date.month) | |
DMday2 = str(last_DM_date.day) | |
last_date='{0}{1}{2}.tif'.format(DMyear2.zfill(4), DMmonth2.zfill(2), DMday2.zfill(2)) | |
print("All DRY Month data is available") | |
# Run the script | |
def create_CDM(_CDM_folder, _tiffolder, threshold): | |
CDM_Date_List = create_CDM_List(_CDM_folder) | |
Monthly_list = create_monthly_List(_tiffolder) | |
# if there is no DRY data, creating new DRY data | |
if len(CDM_Date_List)==0: | |
print("No Consecutive DRY Month data found...") | |
print("Creating first Consecutive DRY Month data...") | |
execute_first_CDM(_tiffolder, _CDM_folder, threshold) | |
CDM_Date_List = create_CDM_List(_CDM_folder) | |
# if there is Consecutive DRY Month data | |
print("Consecutive DRY Month data found. Looking for latest Consecutive DRY Month data...") | |
#Check last Consecutive DRY Month available | |
last_date = max(CDM_Date_List) | |
#Check last monthly data availabke | |
max_monthly_date = max(Monthly_list) | |
last_CDM_date = date(int(last_date[0:4]), int(last_date[4:6]), int(last_date[6:8])) | |
last_monthly_date = date(int(max_monthly_date[0:4]), int(max_monthly_date[4:6]), int(max_monthly_date[6:8])) | |
# process Consecutive DRY Month to every monthly data available after last Consecutive DRY Month data | |
while last_monthly_date + relativedelta(months=1) > last_CDM_date: | |
execute_CDM(last_date, _tiffolder, _CDM_folder, threshold) | |
last_CDM_date=last_CDM_date+relativedelta(months=1) | |
CDMyear2 = str(last_CDM_date.year) | |
CDMmonth2 = str(last_CDM_date.month) | |
CDMday2 = str(last_CDM_date.day) | |
last_date='{0}{1}{2}.tif'.format(CDMyear2.zfill(4), CDMmonth2.zfill(2), CDMday2.zfill(2)) | |
print("All Consecutive DRY Month data is available") | |
# Execute sum of DRY Month | |
def execute_SUM(output_folder, folder_to_extract): | |
listoffile = [] | |
for data in os.listdir(folder_to_extract): | |
if data.endswith(".tif"): | |
listoffile.append(os.path.join(folder_to_extract, data)) | |
print("data to calculate is "+str(len(listoffile))) | |
print("start running cell statistics to find total number of DRY Month in 1958-2021.....") | |
arcpy.CheckOutExtension("spatial") | |
sum_data_filename = 'wld_cli_terraclimate_spei12_dry_duration_total_1958_2021.tif' | |
sum_data = arcpy.sa.CellStatistics(listoffile, "SUM", "DATA") | |
sum_data.save(os.path.join(output_folder, sum_data_filename)) | |
print(sum_data_filename + ' is succesfully created') | |
arcpy.CheckInExtension("spatial") | |
# Execute max of Consective DRY Month | |
def execute_MAX(output_folder, folder_to_extract): | |
listoffile = [] | |
for data in os.listdir(folder_to_extract): | |
if data.endswith(".tif"): | |
listoffile.append(os.path.join(folder_to_extract, data)) | |
print("data to calculate is "+str(len(listoffile))) | |
print("start running cell statistics to find maximum Consecutive DRY Month in 1958-2021.....") | |
arcpy.CheckOutExtension("spatial") | |
max_data_filename = 'wld_cli_terraclimate_spei12_dry_duration_max_1958_2021.tif' | |
max_data = arcpy.sa.CellStatistics(listoffile, "MAXIMUM", "DATA") | |
max_data.save(os.path.join(output_folder, max_data_filename)) | |
print(max_data_filename + ' is succesfully created') | |
arcpy.CheckInExtension("spatial") | |
# Let's go! | |
if __name__ == '__main__': | |
# Global Environment settings | |
with arcpy.EnvManager(scratchWorkspace=r"X:\ArcGIS_TEMP\Scratch.gdb", \ | |
workspace=r"X:\ArcGIS_TEMP\Default.gdb"): | |
# Run the function (output folder, input folder, threshold) | |
create_CDM('Z:\\Temp\\terraclimate\\spei\\output\\spei12\\geotiff\\consecutive_dry_month',\ | |
'Z:\\Temp\\terraclimate\\spei\\output\\spei12\\geotiff\\gamma',-1.2) | |
# Run the function (output folder, input folder, threshold) | |
create_DM('Z:\\Temp\\terraclimate\\spei\\output\\spei12\\geotiff\\dry_month',\ | |
'Z:\\Temp\\terraclimate\\spei\\output\\spei12\\geotiff\\gamma',-1.2) | |
# Run the function (output folder, input folder) | |
execute_MAX('Z:\\Temp\\terraclimate\\spei\\output\\spei12\\geotiff\\consecutive_dry_month_max',\ | |
'Z:\\Temp\\terraclimate\\spei\\output\\spei12\\geotiff\\consecutive_dry_month') | |
# Run the function (output folder, input folder) | |
execute_SUM('Z:\\Temp\\terraclimate\\spei\\output\\spei12\\geotiff\\dry_month_total',\ | |
'Z:\\Temp\\terraclimate\\spei\\output\\spei12\\geotiff\\dry_month') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment