diff --git a/src/vector/v.surf.icw/v.surf.icw.html b/src/vector/v.surf.icw/v.surf.icw.html index 06682ed369..0731f43258 100644 --- a/src/vector/v.surf.icw/v.surf.icw.html +++ b/src/vector/v.surf.icw/v.surf.icw.html @@ -51,11 +51,20 @@

NOTES

-->

By default the module will run serially. To run in parallel set the -workers parameter to the desired value (typically the number +nprocs parameter to the desired value (typically the number of cores in your CPU). Alternatively, if the WORKERS environment variable is set, the number of concurrent processes will be set at that number of jobs. +

+ + v.surf.icw example +
+ ICW interpolation of surface salinity in Chalky and Preservation Inlets, + Fiordland, New Zealand +
+

EXAMPLE

@@ -134,5 +143,6 @@

SEE ALSO

AUTHOR

Hamish Bowman
-Department of Marine Science,
+Department of Geology
+University of Otago
Dunedin, New Zealand
diff --git a/src/vector/v.surf.icw/v.surf.icw.py b/src/vector/v.surf.icw/v.surf.icw.py index 349e5258ff..f469926f14 100755 --- a/src/vector/v.surf.icw/v.surf.icw.py +++ b/src/vector/v.surf.icw/v.surf.icw.py @@ -1,8 +1,7 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 ############################################################################# # # MODULE: v.surf.icw -# version $Id$ # # AUTHOR: M. Hamish Bowman, Dunedin, New Zealand # Originally written aboard the NZ DoC ship M/V Renown, @@ -13,7 +12,7 @@ # PURPOSE: Like IDW interpolation, but distance is cost to get to any # other site. # -# COPYRIGHT: (c) 2003-2014 Hamish Bowman +# COPYRIGHT: (c) 2003-2024 Hamish Bowman # This program is free software under the GNU General Public # License (>=v2). Read the file COPYING that comes with GRASS # for details. @@ -44,25 +43,14 @@ # % keyword: interpolation # % keyword: ICW # %End -# %option -# % key: input -# % type: string -# % gisprompt: old,vector,vector -# % description: Name of existing vector points map containing seed data -# % required : yes +# %option G_OPT_V_INPUT +# % label: Name of existing vector points map containing seed data # %end -# %option -# % key: column -# % type: string +# %option G_OPT_DB_COLUMN # % description: Column name in points map that contains data values # % required : yes # %end -# %option -# % key: output -# % type: string -# % gisprompt: new,cell,raster -# % description: Name for output raster map -# % required : yes +# %option G_OPT_R_OUTPUT # %end # %option # % key: cost_map @@ -79,19 +67,11 @@ # % options: 1-6 # % required : no # %end -# %option -# % key: layer +# %option G_OPT_V_FIELD # % type: integer -# % answer: 1 -# % description: Layer number of data in points map -# % required: no +# % label: Layer number of data in points map # %end -# %option -# % key: where -# % type: string -# % label: WHERE conditions of SQL query statement without 'where' keyword -# % description: Example: income < 1000 and inhab >= 10000 -# % required : no +# %option G_OPT_DB_WHERE # %end ##%option @@ -112,11 +92,8 @@ # % key: r # % description: Use (d^n)*log(d) instead of 1/(d^n) for radial basis function # %end -# %option -# % key: workers -# % type: integer -# % options: 1-256 -# % answer: 1 +# %option G_OPT_M_NPROCS +# % options: 1-1024 # % description: Number of parallel processes to launch # %end @@ -135,14 +112,15 @@ def cleanup(): grass.verbose(_("Cleanup..")) tmp_base = "tmp_icw_" + str(os.getpid()) + "_" - grass.run_command( - "g.remove", flags="f", type="raster", pattern=tmp_base + "*", quiet=True - ) - grass.try_remove(TMP_FILE) + # grass.run_command('g.list', type='raster', mapset='.', flags='p') + result = grass.list_strings("raster", pattern=tmp_base + "*", mapset=".") + if len(result) > 0: + grass.run_command( + "g.remove", flags="f", type="raster", pattern=tmp_base + "*", quiet=True + ) def main(): - pts_input = options["input"] output = options["output"] cost_map = options["cost_map"] @@ -151,7 +129,7 @@ def main(): friction = float(options["friction"]) layer = options["layer"] where = options["where"] - workers = int(options["workers"]) + workers = int(options["nprocs"]) if workers == 1 and "WORKERS" in os.environ: workers = int(os.environ["WORKERS"]) @@ -267,20 +245,21 @@ def main(): northing = position[1] cat = int(position[-1]) + # FIXME: layer=layer probably needed here # retrieve data value from vector's attribute table: data_value = grass.vector_db_select(pts_input, columns=column)["values"][cat][0] if not data_value: - grass.message( + grass.verbose( _("Site %d of %d, e=%.4f n=%.4f cat=%d data=?") % (num, n, float(easting), float(northing), cat) ) - grass.message(_(" -- Skipping, no data here.")) + grass.verbose(_(" -- Skipping, no data here.")) del points_list[num - 1] n -= 1 continue else: - grass.message( + grass.verbose( _("Site %d of %d, e=%.4f n=%.4f cat=%d data=%.8g") % (num, n, float(easting), float(northing), cat, float(data_value)) ) @@ -296,7 +275,7 @@ def main(): .split("|")[-1] ) if rast_val == "*": - grass.message(_(" -- Skipping, point lays outside of cost_map.")) + grass.verbose(_(" -- Skipping, point lays outside of cost_map.")) del points_list[num - 1] n -= 1 continue @@ -327,6 +306,7 @@ def main(): if proc[i].wait() != 0: grass.fatal(_("Problem running %s") % "r.cost") + grass.verbose("\n") grass.message(_("Removing anomalies at site positions ...")) proc = {} @@ -345,7 +325,7 @@ def main(): ) # stall to wait for the nth worker to complete, if (i + 1) % workers == 0: - # print 'stalling ...' + # print('stalling ...') proc[i].wait() # make sure everyone is finished @@ -393,7 +373,7 @@ def main(): ) # stall to wait for the nth worker to complete, if (i + 1) % workers == 0: - # print 'stalling ...' + # print('stalling ...') proc[i].wait() # r.patch in=1by_cost_site_sqrd.${NUM},tmp_idw_cost_val_$$ out=1by_cost_site_sqrd.${NUM} --o @@ -415,8 +395,7 @@ def main(): ####################################################### #### Step 3) find sum(cost^2) - grass.verbose("") - grass.verbose(_("Finding sum of squares ...")) + grass.verbose("\n" + _("Finding sum of squares ...")) # todo: test if MASK exists already, fatal exit if it does? if post_mask: @@ -425,14 +404,12 @@ def main(): grass.message(_("Summation of cost weights ...")) - input_maps = tmp_base + "1by_cost_site_sq.%05d" % 1 - - global TMP_FILE TMP_FILE = grass.tempfile() with open(TMP_FILE, "w") as maplist: - for i in range(2, n + 1): + for i in range(1, n + 1): mapname = "%s1by_cost_site_sq.%05d" % (tmp_base, i) maplist.write(mapname + "\n") + maplist.close() # grass.run_command('g.list', type = 'raster', mapset = '.') @@ -444,13 +421,15 @@ def main(): except CalledModuleError: grass.fatal(_("Problem running %s") % "r.series") + grass.try_remove(TMP_FILE) + if post_mask: grass.message(_("Removing post_mask <%s>"), post_mask) grass.run_command("g.remove", flags="f", name="MASK", quiet=True) ####################################################### #### Step 4) ( 1/di^2 / sum(1/d^2) ) * ai - grass.verbose("") + grass.verbose("\n") grass.message(_("Creating partial weights ...")) proc = {} @@ -459,17 +438,18 @@ def main(): easting = position[0] northing = position[1] cat = int(position[-1]) + # FIXME: layer=layer probably needed here data_value = grass.vector_db_select(pts_input, columns=column)["values"][cat][0] data_value = float(data_value) # failsafe: at this point the data values should all be valid if not data_value: - grass.message(_("Site %d of %d, cat = %d, data value = ?") % (num, n, cat)) - grass.message(_(" -- Skipping, no data here. [Probably programmer error]")) + grass.verbose(_("Site %d of %d, cat = %d, data value = ?") % (num, n, cat)) + grass.verbose(_(" -- Skipping, no data here. [Probably programmer error]")) n -= 1 continue else: - grass.message( + grass.verbose( _("Site %d of %d, cat = %d, data value = %.8g") % (num, n, cat, data_value) ) @@ -485,7 +465,7 @@ def main(): .split("|")[-1] ) if rast_val == "*": - grass.message( + grass.verbose( _( " -- Skipping, point lays outside of cost_map. [Probably programmer error]" ) @@ -534,23 +514,31 @@ def main(): # grass.run_command('g.list', type = 'raster', mapset = '.') ####################################################### - grass.message("") + grass.verbose("\n") grass.message(_("Calculating final values ...")) - input_maps = tmp_base + "partial.%05d" % 1 - for i in range(2, n + 1): - input_maps += ",%spartial.%05d" % (tmp_base, i) + TMP_FILE = grass.tempfile() + with open(TMP_FILE, "w") as maplist: + for i in range(1, n + 1): + mapname = "%spartial.%05d" % (tmp_base, i) + maplist.write(mapname + "\n") + maplist.close() try: - grass.run_command("r.series", method="sum", input=input_maps, output=output) + grass.run_command("r.series", method="sum", file=TMP_FILE, output=output) except CalledModuleError: grass.fatal(_("Problem running %s") % "r.series") + grass.try_remove(TMP_FILE) + # TODO: r.patch in v.to.rast of values at exact seed site locations. currently set to null grass.run_command("r.colors", map=output, color="bcyr", quiet=True) grass.run_command( - "r.support", map=output, history="", title="Inverse cost-weighted interpolation" + "r.support", + map=output, + history=" ", + title="Inverse cost-weighted interpolation", ) grass.run_command("r.support", map=output, history="v.surf.icw interpolation:") grass.run_command( @@ -558,6 +546,7 @@ def main(): map=output, history=" input map=" + pts_input + " attribute column=" + column, ) + # FIXME: if layer !=1 then (layer="$layer") probably needed here grass.run_command( "r.support", map=output, diff --git a/src/vector/v.surf.icw/v_surf_icw_salinity.png b/src/vector/v.surf.icw/v_surf_icw_salinity.png new file mode 100644 index 0000000000..a180f158b4 Binary files /dev/null and b/src/vector/v.surf.icw/v_surf_icw_salinity.png differ