From 98ff93e525c6da2547d5d5f1bff8e3f9831be6a2 Mon Sep 17 00:00:00 2001 From: fkroeber Date: Mon, 16 Aug 2021 17:32:23 +0200 Subject: [PATCH 1/8] adjustments to t.rast.aggregate & aggregation.py: enable weighted aggregations --- python/grass/temporal/aggregation.py | 75 ++++++- temporal/t.rast.aggregate/t.rast.aggregate.py | 192 +++++++++--------- 2 files changed, 167 insertions(+), 100 deletions(-) diff --git a/python/grass/temporal/aggregation.py b/python/grass/temporal/aggregation.py index 095780f366e..058a6006e4f 100644 --- a/python/grass/temporal/aggregation.py +++ b/python/grass/temporal/aggregation.py @@ -221,6 +221,7 @@ def aggregate_by_topology( nprocs=1, spatial=None, dbif=None, + weighting=False, overwrite=False, file_limit=1000, ): @@ -258,7 +259,7 @@ def aggregate_by_topology( msgr = get_tgis_message_interface() - dbif, connection_state_changed = init_dbif(dbif) + dbif, connected = init_dbif(dbif) topo_builder = SpatioTemporalTopologyBuilder() topo_builder.build(mapsA=granularity_list, mapsB=map_list, spatial=spatial) @@ -316,6 +317,47 @@ def aggregate_by_topology( if "overlapped" in topo_list and granule.overlapped: for map_layer in granule.overlapped: aggregation_list.append(map_layer.get_name()) + if "related" in topo_list: + aggregation_weights = [] + set_list = set() + try: + for map_layer in granule.overlaps: + set_list.add(map_layer) + except: + pass + try: + for map_layer in granule.overlapped: + set_list.add(map_layer) + except: + pass + try: + for map_layer in granule.contains: + set_list.add(map_layer) + except: + pass + try: + for map_layer in granule.equal: + set_list.add(map_layer) + except: + pass + try: + for map_layer in granule.during: + set_list.add(map_layer) + except: + pass + if set_list: + for map_layer in set_list: + aggregation_list.append(map_layer.get_name()) + t_granule_contained = map_layer.get_absolute_time() + t_granule = granule.get_absolute_time() + if None in t_granule_contained or None in t_granule: + aggregation_weights.append(0) + else: + overlap_abs = min(t_granule[1], t_granule_contained[1]) - max( + t_granule[0], t_granule_contained[0] + ) + overlap_rel = overlap_abs / (t_granule[1] - t_granule[0]) + aggregation_weights.append(overlap_rel) if aggregation_list: msgr.verbose( @@ -360,11 +402,18 @@ def aggregate_by_topology( # Create the r.series input file filename = gscript.tempfile(True) file = open(filename, "w") - for name in aggregation_list: - string = "%s\n" % (name) - file.write(string) - file.close() - + if weighting: + for i, name in enumerate(aggregation_list): + string = name + weight = aggregation_weights[i] + file.write("%s|%f\n" % (string, weight)) + file.close() + else: + for name in aggregation_list: + string = "%s\n" % (name) + file.write(string) + file.close() + # Perform aggregation mod = copy.deepcopy(r_series) mod(file=filename, output=output_name) if len(aggregation_list) > int(file_limit): @@ -380,13 +429,21 @@ def aggregate_by_topology( mod(flags="z") process_queue.put(mod) else: - mod = copy.deepcopy(g_copy) - mod(raster=[aggregation_list[0], output_name]) + if weighting: + mod = copy.deepcopy(r_series) + mod( + input=aggregation_list[0], + output=output_name, + weights=aggregation_weights[0], + ) + else: + mod = copy.deepcopy(g_copy) + mod(raster=[aggregation_list[0], output_name]) process_queue.put(mod) process_queue.wait() - if connection_state_changed: + if connected: dbif.close() msgr.percent(1, 1, 1) diff --git a/temporal/t.rast.aggregate/t.rast.aggregate.py b/temporal/t.rast.aggregate/t.rast.aggregate.py index 1002324af9b..427b885a63b 100755 --- a/temporal/t.rast.aggregate/t.rast.aggregate.py +++ b/temporal/t.rast.aggregate/t.rast.aggregate.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 - +# -*- coding: utf-8 -*- ############################################################################ # # MODULE: t.rast.aggregate @@ -20,96 +20,101 @@ # ############################################################################# -# %module -# % description: Aggregates temporally the maps of a space time raster dataset by a user defined granularity. -# % keyword: temporal -# % keyword: aggregation -# % keyword: raster -# % keyword: time -# %end - -# %option G_OPT_STRDS_INPUT -# %end - -# %option G_OPT_STRDS_OUTPUT -# %end - -# %option -# % key: basename -# % type: string -# % label: Basename of the new generated output maps -# % description: Either a numerical suffix or the start time (s-flag) separated by an underscore will be attached to create a unique identifier -# % required: yes -# % multiple: no -# % gisprompt: -# %end - -# %option -# % key: suffix -# % type: string -# % 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) -# % answer: gran -# % required: no -# % multiple: no -# %end - -# %option -# % key: granularity -# % type: string -# % 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 -# % required: yes -# % multiple: no -# %end - -# %option -# % key: method -# % type: string -# % description: Aggregate operation to be performed on the raster maps -# % required: yes -# % multiple: no -# % 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 -# % answer: average -# %end - -# %option -# % key: offset -# % type: integer -# % description: Offset that is used to create the output map ids, output map id is generated as: basename_ (count + offset) -# % required: no -# % multiple: no -# % answer: 0 -# %end - -# %option -# % key: nprocs -# % type: integer -# % description: Number of r.series processes to run in parallel -# % required: no -# % multiple: no -# % answer: 1 -# %end - -# %option -# % key: file_limit -# % type: integer -# % description: The maximum number of open files allowed for each r.series process -# % required: no -# % multiple: no -# % answer: 1000 -# %end - -# %option G_OPT_T_SAMPLE -# % options: equal,overlaps,overlapped,starts,started,finishes,finished,during,contains -# % answer: contains -# %end - -# %option G_OPT_T_WHERE -# %end - -# %flag -# % key: n -# % description: Register Null maps -# %end +#%module +#% description: Aggregates temporally the maps of a space time raster dataset by a user defined granularity. +#% keyword: temporal +#% keyword: aggregation +#% keyword: raster +#% keyword: time +#%end + +#%option G_OPT_STRDS_INPUT +#%end + +#%option G_OPT_STRDS_OUTPUT +#%end + +#%option +#% key: basename +#% type: string +#% label: Basename of the new generated output maps +#% description: Either a numerical suffix or the start time (s-flag) separated by an underscore will be attached to create a unique identifier +#% required: yes +#% multiple: no +#% gisprompt: +#%end + +#%option +#% key: suffix +#% type: string +#% 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) +#% answer: gran +#% required: no +#% multiple: no +#%end + +#%option +#% key: granularity +#% type: string +#% 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 +#% required: yes +#% multiple: no +#%end + +#%option +#% key: method +#% type: string +#% description: Aggregate operation to be performed on the raster maps +#% required: yes +#% multiple: no +#% 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 +#% answer: average +#%end + +#%option +#% key: offset +#% type: integer +#% description: Offset that is used to create the output map ids, output map id is generated as: basename_ (count + offset) +#% required: no +#% multiple: no +#% answer: 0 +#%end + +#%option +#% key: nprocs +#% type: integer +#% description: Number of r.series processes to run in parallel +#% required: no +#% multiple: no +#% answer: 1 +#%end + +#%option +#% key: file_limit +#% type: integer +#% description: The maximum number of open files allowed for each r.series process +#% required: no +#% multiple: no +#% answer: 1000 +#%end + +#%option G_OPT_T_SAMPLE +#% options: equal,overlaps,overlapped,starts,started,finishes,finished,during,contains,related +#% answer: contains +#%end + +#%option G_OPT_T_WHERE +#%end + +#%flag +#% key: n +#% description: Register Null maps +#%end + +#%flag +#% key: w +#% description: Aggregation weighted by temporal overlap between input rasters and rasters of defined granularity +#%end import grass.script as gcore @@ -128,6 +133,7 @@ def main(): gran = options["granularity"] base = options["basename"] register_null = flags["n"] + weighting = flags["w"] method = options["method"] sampling = options["sampling"] offset = options["offset"] @@ -135,6 +141,9 @@ def main(): file_limit = options["file_limit"] time_suffix = options["suffix"] + if weighting and not sampling == "related": + gcore.fatal(_("Weighting only works with method 'related'")) + topo_list = sampling.split(",") tgis.init() @@ -203,6 +212,7 @@ def main(): method=method, nprocs=nprocs, spatial=None, + weighting=weighting, overwrite=gcore.overwrite(), file_limit=file_limit, ) From 801b29e3690914e34c2c0b2440993c67bd57e8a4 Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Tue, 30 Nov 2021 20:45:16 +0100 Subject: [PATCH 2/8] revert undesired changes --- temporal/t.rast.aggregate/t.rast.aggregate.py | 189 +++++++++--------- 1 file changed, 94 insertions(+), 95 deletions(-) diff --git a/temporal/t.rast.aggregate/t.rast.aggregate.py b/temporal/t.rast.aggregate/t.rast.aggregate.py index 427b885a63b..1b663f496b2 100755 --- a/temporal/t.rast.aggregate/t.rast.aggregate.py +++ b/temporal/t.rast.aggregate/t.rast.aggregate.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- ############################################################################ # # MODULE: t.rast.aggregate @@ -21,100 +20,100 @@ ############################################################################# #%module -#% description: Aggregates temporally the maps of a space time raster dataset by a user defined granularity. -#% keyword: temporal -#% keyword: aggregation -#% keyword: raster -#% keyword: time -#%end - -#%option G_OPT_STRDS_INPUT -#%end - -#%option G_OPT_STRDS_OUTPUT -#%end - -#%option -#% key: basename -#% type: string -#% label: Basename of the new generated output maps -#% description: Either a numerical suffix or the start time (s-flag) separated by an underscore will be attached to create a unique identifier -#% required: yes -#% multiple: no -#% gisprompt: -#%end - -#%option -#% key: suffix -#% type: string -#% 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) -#% answer: gran -#% required: no -#% multiple: no -#%end - -#%option -#% key: granularity -#% type: string -#% 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 -#% required: yes -#% multiple: no -#%end - -#%option -#% key: method -#% type: string -#% description: Aggregate operation to be performed on the raster maps -#% required: yes -#% multiple: no -#% 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 -#% answer: average -#%end - -#%option -#% key: offset -#% type: integer -#% description: Offset that is used to create the output map ids, output map id is generated as: basename_ (count + offset) -#% required: no -#% multiple: no -#% answer: 0 -#%end - -#%option -#% key: nprocs -#% type: integer -#% description: Number of r.series processes to run in parallel -#% required: no -#% multiple: no -#% answer: 1 -#%end - -#%option -#% key: file_limit -#% type: integer -#% description: The maximum number of open files allowed for each r.series process -#% required: no -#% multiple: no -#% answer: 1000 -#%end - -#%option G_OPT_T_SAMPLE -#% options: equal,overlaps,overlapped,starts,started,finishes,finished,during,contains,related -#% answer: contains -#%end - -#%option G_OPT_T_WHERE -#%end - -#%flag -#% key: n -#% description: Register Null maps -#%end - -#%flag -#% key: w -#% description: Aggregation weighted by temporal overlap between input rasters and rasters of defined granularity -#%end +# % description: Aggregates temporally the maps of a space time raster dataset by a user defined granularity. +# % keyword: temporal +# % keyword: aggregation +# % keyword: raster +# % keyword: time +# %end + +# %option G_OPT_STRDS_INPUT +# %end + +# %option G_OPT_STRDS_OUTPUT +# %end + +# %option +# % key: basename +# % type: string +# % label: Basename of the new generated output maps +# % description: Either a numerical suffix or the start time (s-flag) separated by an underscore will be attached to create a unique identifier +# % required: yes +# % multiple: no +# % gisprompt: +# %end + +# %option +# % key: suffix +# % type: string +# % 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) +# % answer: gran +# % required: no +# % multiple: no +# %end + +# %option +# % key: granularity +# % type: string +# % 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 +# % required: yes +# % multiple: no +# %end + +# %option +# % key: method +# % type: string +# % description: Aggregate operation to be performed on the raster maps +# % required: yes +# % multiple: no +# % 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 +# % answer: average +# %end + +# %option +# % key: offset +# % type: integer +# % description: Offset that is used to create the output map ids, output map id is generated as: basename_ (count + offset) +# % required: no +# % multiple: no +# % answer: 0 +# %end + +# %option +# % key: nprocs +# % type: integer +# % description: Number of r.series processes to run in parallel +# % required: no +# % multiple: no +# % answer: 1 +# %end + +# %option +# % key: file_limit +# % type: integer +# % description: The maximum number of open files allowed for each r.series process +# % required: no +# % multiple: no +# % answer: 1000 +# %end + +# %option G_OPT_T_SAMPLE +# % options: equal,overlaps,overlapped,starts,started,finishes,finished,during,contains,related +# % answer: contains +# %end + +# %option G_OPT_T_WHERE +# %end + +# %flag +# % key: n +# % description: Register Null maps +# %end + +# %flag +# % key: w +# % description: Aggregation weighted by temporal overlap between input rasters and rasters of defined granularity +# %end import grass.script as gcore From 1ec77c43f62d56d574fb4b6f22ee6615e8805c9a Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Tue, 30 Nov 2021 20:47:11 +0100 Subject: [PATCH 3/8] restore blanks --- temporal/t.rast.aggregate/t.rast.aggregate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/temporal/t.rast.aggregate/t.rast.aggregate.py b/temporal/t.rast.aggregate/t.rast.aggregate.py index 1b663f496b2..967543dd163 100755 --- a/temporal/t.rast.aggregate/t.rast.aggregate.py +++ b/temporal/t.rast.aggregate/t.rast.aggregate.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 + ############################################################################ # # MODULE: t.rast.aggregate @@ -19,7 +20,7 @@ # ############################################################################# -#%module +# %module # % description: Aggregates temporally the maps of a space time raster dataset by a user defined granularity. # % keyword: temporal # % keyword: aggregation From 013ae4df459b6756b11fc7b920dbde47f181a541 Mon Sep 17 00:00:00 2001 From: Guido Riembauer Date: Fri, 3 Dec 2021 08:58:18 +0100 Subject: [PATCH 4/8] VP review --- python/grass/temporal/aggregation.py | 56 ++++++++----------- .../t.rast.aggregate/t.rast.aggregate.html | 31 ++++++++++ temporal/t.rast.aggregate/t.rast.aggregate.py | 2 +- .../testsuite/test_aggregation_absolute.py | 41 +++++++++++++- 4 files changed, 95 insertions(+), 35 deletions(-) diff --git a/python/grass/temporal/aggregation.py b/python/grass/temporal/aggregation.py index 058a6006e4f..21b388952d1 100644 --- a/python/grass/temporal/aggregation.py +++ b/python/grass/temporal/aggregation.py @@ -259,7 +259,7 @@ def aggregate_by_topology( msgr = get_tgis_message_interface() - dbif, connected = init_dbif(dbif) + dbif, connection_state_changed = init_dbif(dbif) topo_builder = SpatioTemporalTopologyBuilder() topo_builder.build(mapsA=granularity_list, mapsB=map_list, spatial=spatial) @@ -289,7 +289,6 @@ def aggregate_by_topology( count += 1 aggregation_list = [] - if "equal" in topo_list and granule.equal: for map_layer in granule.equal: aggregation_list.append(map_layer.get_name()) @@ -320,45 +319,40 @@ def aggregate_by_topology( if "related" in topo_list: aggregation_weights = [] set_list = set() - try: + if granule.overlaps: for map_layer in granule.overlaps: set_list.add(map_layer) - except: - pass - try: + if granule.overlapped: for map_layer in granule.overlapped: set_list.add(map_layer) - except: - pass - try: + if granule.contains: for map_layer in granule.contains: set_list.add(map_layer) - except: - pass - try: + if granule.equal: for map_layer in granule.equal: set_list.add(map_layer) - except: - pass - try: + if granule.during: for map_layer in granule.during: set_list.add(map_layer) - except: - pass - if set_list: + if len(set_list) > 0: for map_layer in set_list: aggregation_list.append(map_layer.get_name()) t_granule_contained = map_layer.get_absolute_time() t_granule = granule.get_absolute_time() if None in t_granule_contained or None in t_granule: + # no weight for this map_layer because no + # overlap whatsoever aggregation_weights.append(0) else: + # calculate the absolute temporal overlap between the + # new granule and the map_layer overlap_abs = min(t_granule[1], t_granule_contained[1]) - max( t_granule[0], t_granule_contained[0] ) + # calculate the relative percentage of the overlap + # with respect to the total granule duration overlap_rel = overlap_abs / (t_granule[1] - t_granule[0]) aggregation_weights.append(overlap_rel) - if aggregation_list: msgr.verbose( _("Aggregating %(len)i raster maps from %(start)s to" " %(end)s") @@ -401,18 +395,16 @@ def aggregate_by_topology( if len(aggregation_list) > 1: # Create the r.series input file filename = gscript.tempfile(True) - file = open(filename, "w") - if weighting: - for i, name in enumerate(aggregation_list): - string = name - weight = aggregation_weights[i] - file.write("%s|%f\n" % (string, weight)) - file.close() - else: - for name in aggregation_list: - string = "%s\n" % (name) - file.write(string) - file.close() + with open(filename, "w") as file: + if weighting: + for i, name in enumerate(aggregation_list): + string = name + weight = aggregation_weights[i] + file.write("%s|%f\n" % (string, weight)) + else: + for name in aggregation_list: + string = "%s\n" % (name) + file.write(string) # Perform aggregation mod = copy.deepcopy(r_series) mod(file=filename, output=output_name) @@ -443,7 +435,7 @@ def aggregate_by_topology( process_queue.wait() - if connected: + if connection_state_changed: dbif.close() msgr.percent(1, 1, 1) diff --git a/temporal/t.rast.aggregate/t.rast.aggregate.html b/temporal/t.rast.aggregate/t.rast.aggregate.html index b4e797abace..8fe3b48efc0 100644 --- a/temporal/t.rast.aggregate/t.rast.aggregate.html +++ b/temporal/t.rast.aggregate/t.rast.aggregate.html @@ -194,6 +194,37 @@

Yearly aggregation

yearly_avg_temp_2004|climate|2004-01-01 00:00:00|2005-01-01 00:00:00 +

Weighted aggregation

+In this example, we create a STRDS of fictional temperature values for +a weekly interval: +
+MAPS="map_1 map_2 map_3 map_4 map_5 map_6 map_7 map_8 map_9 map_10"
+for map in ${MAPS} ; do
+    r.surf.random output=${map} min=278 max=298
+    echo ${map} >> map_list.txt
+done
+
+t.create type=strds temporaltype=absolute \
+         output=temperature_weekly \
+         title="Weekly Temperature" \
+         description="Test dataset with weekly temperature"
+
+t.register -i type=raster input=temperature_weekly \
+          file=map_list.txt start="2021-05-01" increment="1 weeks"
+
+ +We can now use the -w flag and the sampling=related option +to calculate the 10-daily average temperature. The values of each 10-days +granule are calculated weighted by relative temporal coverage of the input +granules. +
+t.rast.aggregate input=temperature_weekly output=temperature_10daily_weighted \
+  basename=tendaily_temp_weighted method=average granularity="10 days" \
+  sampling=related -w
+
+This is especially useful when harmonizing STRDS with granules that are not +integer multiplications of each other. +

SEE ALSO

diff --git a/temporal/t.rast.aggregate/t.rast.aggregate.py b/temporal/t.rast.aggregate/t.rast.aggregate.py index 967543dd163..1024dc42156 100755 --- a/temporal/t.rast.aggregate/t.rast.aggregate.py +++ b/temporal/t.rast.aggregate/t.rast.aggregate.py @@ -142,7 +142,7 @@ def main(): time_suffix = options["suffix"] if weighting and not sampling == "related": - gcore.fatal(_("Weighting only works with method 'related'")) + gcore.fatal(_("Weighting only works with sampling: 'related'")) topo_list = sampling.split(",") diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py index 2056a654f7c..4d75b27079f 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py @@ -55,11 +55,11 @@ def setUpClass(cls): def tearDownClass(cls): """Remove the temporary region""" cls.del_temp_region() - cls.runModule("t.remove", flags="df", type="strds", inputs="A") + cls.runModule("t.remove", flags="rf", type="strds", inputs="A") def tearDown(self): """Remove generated data""" - self.runModule("t.remove", flags="df", type="strds", inputs="B") + self.runModule("t.remove", flags="rf", type="strds", inputs="B") def test_disaggregation(self): """Disaggregation with empty maps""" @@ -236,6 +236,43 @@ def test_aggregation_3months(self): maps = "b_101" + os.linesep self.assertEqual(maps, lister.outputs.stdout) + def test_weighted_aggregation(self): + """Weighted aggregation to 3 weeks""" + self.assertModule( + "t.rast.aggregate", + input="A", + output="B", + basename="b", + granularity="3 weeks", + method="average", + sampling=["related"], + file_limit=0, + suffix="num%03", + flags="w", + ) + # assert that there are 5 rasters + t_rast_list = SimpleModule("t.rast.list", input="B", flags="u").run() + rasters = [ + item + for item in t_rast_list.outputs.stdout.split(os.linesep) + if (len(item) > 0 and item.startswith("b_")) + ] + self.assertEqual( + 5, + len(rasters), + ("Output STRDS does not contain the correct number of rasters."), + ) + + # assert that the granularity is correct and the whole time range is + # covered + info = SimpleModule("t.info", flags="g", input="B") + ref_dict = { + "start_time": "'2001-01-15 00:00:00'", + "end_time": "'2001-04-30 00:00:00'", + "granularity": "'21 days'", + } + self.assertModuleKeyValue(module=info, reference=ref_dict, precision=2, sep="=") + if __name__ == "__main__": from grass.gunittest.main import test From 4e4136ccc5454e522ce89c5f9e2eb4f07e93d530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 17 Oct 2024 02:13:36 +0000 Subject: [PATCH 5/8] style: Fix SIM201 - Use `sampling != "related"` instead of `not sampling == "related"` --- temporal/t.rast.aggregate/t.rast.aggregate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temporal/t.rast.aggregate/t.rast.aggregate.py b/temporal/t.rast.aggregate/t.rast.aggregate.py index bf67f7e2f98..947908e04a1 100755 --- a/temporal/t.rast.aggregate/t.rast.aggregate.py +++ b/temporal/t.rast.aggregate/t.rast.aggregate.py @@ -140,7 +140,7 @@ def main(): file_limit = options["file_limit"] time_suffix = options["suffix"] - if weighting and not sampling == "related": + if weighting and sampling != "related": gcore.fatal(_("Weighting only works with sampling: 'related'")) topo_list = sampling.split(",") From ff88f1ac6e6da410149e6667c4999d80ce5037e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 17 Oct 2024 02:15:10 +0000 Subject: [PATCH 6/8] style: Fix for-loop-set-mutations (FURB142) --- python/grass/temporal/aggregation.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/python/grass/temporal/aggregation.py b/python/grass/temporal/aggregation.py index aad2de12a92..e2069fcdb80 100644 --- a/python/grass/temporal/aggregation.py +++ b/python/grass/temporal/aggregation.py @@ -324,20 +324,15 @@ def aggregate_by_topology( aggregation_weights = [] set_list = set() if granule.overlaps: - for map_layer in granule.overlaps: - set_list.add(map_layer) + set_list.update(granule.overlaps) if granule.overlapped: - for map_layer in granule.overlapped: - set_list.add(map_layer) + set_list.update(granule.overlapped) if granule.contains: - for map_layer in granule.contains: - set_list.add(map_layer) + set_list.update(granule.contains) if granule.equal: - for map_layer in granule.equal: - set_list.add(map_layer) + set_list.update(granule.equal) if granule.during: - for map_layer in granule.during: - set_list.add(map_layer) + set_list.update(granule.during) if len(set_list) > 0: for map_layer in set_list: aggregation_list.append(map_layer.get_name()) From be16ac6068fbb759c275d199d18a6453329f730b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:02:50 -0400 Subject: [PATCH 7/8] Update t.rast.aggregate.py --- temporal/t.rast.aggregate/t.rast.aggregate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temporal/t.rast.aggregate/t.rast.aggregate.py b/temporal/t.rast.aggregate/t.rast.aggregate.py index 947908e04a1..da4c1cba0ba 100755 --- a/temporal/t.rast.aggregate/t.rast.aggregate.py +++ b/temporal/t.rast.aggregate/t.rast.aggregate.py @@ -141,7 +141,7 @@ def main(): time_suffix = options["suffix"] if weighting and sampling != "related": - gcore.fatal(_("Weighting only works with sampling: 'related'")) + gs.fatal(_("Weighting only works with sampling: 'related'")) topo_list = sampling.split(",") From 776d99eae76a7ce69700fcb834887f667c604c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Tue, 22 Oct 2024 17:28:18 -0400 Subject: [PATCH 8/8] Apply suggestions from code review --- python/grass/temporal/aggregation.py | 6 ++---- .../t.rast.aggregate/testsuite/test_aggregation_absolute.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/python/grass/temporal/aggregation.py b/python/grass/temporal/aggregation.py index e2069fcdb80..f21611301bb 100644 --- a/python/grass/temporal/aggregation.py +++ b/python/grass/temporal/aggregation.py @@ -397,10 +397,8 @@ def aggregate_by_topology( filename = gs.tempfile(True) with open(filename, "w") as file: if weighting: - for i, name in enumerate(aggregation_list): - string = name - weight = aggregation_weights[i] - file.write("%s|%f\n" % (string, weight)) + for name, weight in zip(aggregation_list, aggregation_weights): + file.write(f"{name}|{weight}\n") else: for name in aggregation_list: string = "%s\n" % (name) diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py index 9e5f6d51c1e..4791aba9e9a 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py @@ -257,7 +257,7 @@ def test_weighted_aggregation(self): rasters = [ item for item in t_rast_list.outputs.stdout.split(os.linesep) - if (len(item) > 0 and item.startswith("b_")) + if item.startswith("b_") ] self.assertEqual( 5,