1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3############################################################################ 4# 5# MODULE: t.rast.aggregate 6# AUTHOR(S): Soeren Gebbert 7# 8# PURPOSE: Temporally aggregates the maps of a space time raster dataset by a user defined granularity. 9# COPYRIGHT: (C) 2011-2017 by the GRASS Development Team 10# 11# This program is free software; you can redistribute it and/or modify 12# it under the terms of the GNU General Public License as published by 13# the Free Software Foundation; either version 2 of the License, or 14# (at your option) any later version. 15# 16# This program is distributed in the hope that it will be useful, 17# but WITHOUT ANY WARRANTY; without even the implied warranty of 18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19# GNU General Public License for more details. 20# 21############################################################################# 22 23#%module 24#% description: Aggregates temporally the maps of a space time raster dataset by a user defined granularity. 25#% keyword: temporal 26#% keyword: aggregation 27#% keyword: raster 28#% keyword: time 29#%end 30 31#%option G_OPT_STRDS_INPUT 32#%end 33 34#%option G_OPT_STRDS_OUTPUT 35#%end 36 37#%option 38#% key: basename 39#% type: string 40#% label: Basename of the new generated output maps 41#% description: Either a numerical suffix or the start time (s-flag) separated by an underscore will be attached to create a unique identifier 42#% required: yes 43#% multiple: no 44#% gisprompt: 45#%end 46 47#%option 48#% key: suffix 49#% type: string 50#% description: Suffix to add at basename: set 'gran' for granularity, 'time' for the full time format, 'num' for numerical suffix with a specific number of digits (default %05) 51#% answer: gran 52#% required: no 53#% multiple: no 54#%end 55 56#%option 57#% key: granularity 58#% type: string 59#% description: Aggregation granularity, format absolute time "x years, x months, x weeks, x days, x hours, x minutes, x seconds" or an integer value for relative time 60#% required: yes 61#% multiple: no 62#%end 63 64#%option 65#% key: method 66#% type: string 67#% description: Aggregate operation to be performed on the raster maps 68#% required: yes 69#% multiple: no 70#% options: average,count,median,mode,minimum,min_raster,maximum,max_raster,stddev,range,sum,variance,diversity,slope,offset,detcoeff,quart1,quart3,perc90,quantile,skewness,kurtosis 71#% answer: average 72#%end 73 74#%option 75#% key: offset 76#% type: integer 77#% description: Offset that is used to create the output map ids, output map id is generated as: basename_ (count + offset) 78#% required: no 79#% multiple: no 80#% answer: 0 81#%end 82 83#%option 84#% key: nprocs 85#% type: integer 86#% description: Number of r.series processes to run in parallel 87#% required: no 88#% multiple: no 89#% answer: 1 90#%end 91 92#%option 93#% key: file_limit 94#% type: integer 95#% description: The maximum number of open files allowed for each r.series process 96#% required: no 97#% multiple: no 98#% answer: 1000 99#%end 100 101#%option G_OPT_T_SAMPLE 102#% options: equal,overlaps,overlapped,starts,started,finishes,finished,during,contains 103#% answer: contains 104#%end 105 106#%option G_OPT_T_WHERE 107#%end 108 109#%flag 110#% key: n 111#% description: Register Null maps 112#%end 113 114import grass.script as gcore 115 116 117############################################################################ 118 119def main(): 120 # lazy imports 121 import grass.temporal as tgis 122 123 # Get the options 124 input = options["input"] 125 output = options["output"] 126 where = options["where"] 127 gran = options["granularity"] 128 base = options["basename"] 129 register_null = flags["n"] 130 method = options["method"] 131 sampling = options["sampling"] 132 offset = options["offset"] 133 nprocs = options["nprocs"] 134 file_limit = options["file_limit"] 135 time_suffix = options["suffix"] 136 137 topo_list = sampling.split(",") 138 139 tgis.init() 140 141 dbif = tgis.SQLDatabaseInterfaceConnection() 142 dbif.connect() 143 144 sp = tgis.open_old_stds(input, "strds", dbif) 145 146 map_list = sp.get_registered_maps_as_objects(where=where, order="start_time", dbif=dbif) 147 148 if not map_list: 149 dbif.close() 150 gcore.fatal(_("Space time raster dataset <%s> is empty") % input) 151 152 # We will create the strds later, but need to check here 153 tgis.check_new_stds(output, "strds", dbif, gcore.overwrite()) 154 155 start_time = map_list[0].temporal_extent.get_start_time() 156 157 if sp.is_time_absolute(): 158 start_time = tgis.adjust_datetime_to_granularity(start_time, gran) 159 160 # We use the end time first 161 end_time = map_list[-1].temporal_extent.get_end_time() 162 has_end_time = True 163 164 # In case no end time is available, then we use the start time of the last map layer 165 if end_time is None: 166 end_time = map_list[- 1].temporal_extent.get_start_time() 167 has_end_time = False 168 169 granularity_list = [] 170 171 # Build the granularity list 172 while True: 173 if has_end_time is True: 174 if start_time >= end_time: 175 break 176 else: 177 if start_time > end_time: 178 break 179 180 granule = tgis.RasterDataset(None) 181 start = start_time 182 if sp.is_time_absolute(): 183 end = tgis.increment_datetime_by_string(start_time, gran) 184 granule.set_absolute_time(start, end) 185 else: 186 end = start_time + int(gran) 187 granule.set_relative_time(start, end, sp.get_relative_time_unit()) 188 start_time = end 189 190 granularity_list.append(granule) 191 192 output_list = tgis.aggregate_by_topology(granularity_list=granularity_list, granularity=gran, 193 map_list=map_list, 194 topo_list=topo_list, basename=base, time_suffix=time_suffix, 195 offset=offset, method=method, nprocs=nprocs, spatial=None, 196 overwrite=gcore.overwrite(), file_limit=file_limit) 197 198 if output_list: 199 temporal_type, semantic_type, title, description = sp.get_initial_values() 200 output_strds = tgis.open_new_stds(output, "strds", temporal_type, 201 title, description, semantic_type, 202 dbif, gcore.overwrite()) 203 if register_null: 204 register_null=False 205 else: 206 register_null=True 207 208 tgis.register_map_object_list("rast", output_list, output_strds, register_null, 209 sp.get_relative_time_unit(), dbif) 210 211 # Update the raster metadata table entries with aggregation type 212 output_strds.set_aggregation_type(method) 213 output_strds.metadata.update(dbif) 214 215 dbif.close() 216 217if __name__ == "__main__": 218 options, flags = gcore.parser() 219 main() 220