[GRASS-SVN] r57533 - in grass-addons/grass7/raster: . r.sun.hourly

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Aug 28 12:39:21 PDT 2013


Author: annakrat
Date: 2013-08-28 12:39:20 -0700 (Wed, 28 Aug 2013)
New Revision: 57533

Added:
   grass-addons/grass7/raster/r.sun.hourly/
   grass-addons/grass7/raster/r.sun.hourly/Makefile
   grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.html
   grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.py
   grass-addons/grass7/raster/r.sun.hourly/test.r.sun.hourly.sh
Log:
r.sun.hourly: initial version, wrapper script for r.sun, mode 1 (co-author: wenzeslaus)

Added: grass-addons/grass7/raster/r.sun.hourly/Makefile
===================================================================
--- grass-addons/grass7/raster/r.sun.hourly/Makefile	                        (rev 0)
+++ grass-addons/grass7/raster/r.sun.hourly/Makefile	2013-08-28 19:39:20 UTC (rev 57533)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../..
+
+PGM=r.sun.hourly
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script


Property changes on: grass-addons/grass7/raster/r.sun.hourly/Makefile
___________________________________________________________________
Added: svn:mime-type
   + text/x-makefile
Added: svn:eol-style
   + native

Added: grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.html
===================================================================
--- grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.html	                        (rev 0)
+++ grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.html	2013-08-28 19:39:20 UTC (rev 57533)
@@ -0,0 +1,43 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.sun.mode1</em> is a convenient script for running
+r.sun for multiple times in a loop. It corresponds to mode 1
+(see r.sun <a href="r.sun.html">manual page</a>).
+
+<h3>Output parameters explanation</h3>
+Output is one or more series of raster maps.
+
+Series of maps are (if flag <i>t</i> is checked) registered
+to space time raster dataset with absolute time and point time (not interval time).
+Option <i>year</i> has to be specified so that the raster maps can be registered
+to space time dataset or assigned a timestamp. The reason is that it is not possible
+to assign time without date.
+
+For GRASS 6, only timestamp is assigned.
+
+<h2>EXAMPLE</h2>
+
+<div class="code"><pre>
+r.sun.mode1 elev_in=elevation start_time=8 end_time=15 beam_rad_basename=beam nprocs=4 -t
+# show information about newly created space time dataset
+t.info beam
+
+# show raster maps registered in beam dataset
+t.rast.list beam
+</pre></div>
+
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.sun.html">r.sun</a>
+<a href="r.sun.daily.html">r.sun.daily</a> in Addons
+</em>
+
+
+<h2>AUTHOR</h2>
+
+Vaclav Petras, Anna Petrasova<br>
+
+<p>
+<i>Last changed: $Date$</i>


Property changes on: grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.html
___________________________________________________________________
Added: svn:mime-type
   + text/html
Added: svn:keywords
   + Author Date Id
Added: svn:eol-style
   + native

Added: grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.py
===================================================================
--- grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.py	                        (rev 0)
+++ grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.py	2013-08-28 19:39:20 UTC (rev 57533)
@@ -0,0 +1,422 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# MODULE:    r.sun.hourly for GRASS 6 and 7
+# AUTHOR(S): Vaclav Petras, Anna Petrasova
+# PURPOSE:
+# COPYRIGHT: (C) 2013 by the GRASS Development Team
+#
+#                This program is free software under the GNU General Public
+#                License (>=v2). Read the file COPYING that comes with GRASS
+#                for details.
+#
+#############################################################################
+
+#%module
+#% description: Runs r.sun in loop for given time range (mode 1)
+#% keywords: raster
+#% keywords: sun
+#%end
+#%option
+#% type: string
+#% gisprompt: old,cell,raster
+#% key: elev_in
+#% description: Name of the input elevation raster map [meters]
+#% required : yes
+#%end
+#%option
+#% type: string
+#% gisprompt: old,cell,raster
+#% key: asp_in
+#% description: Name of the input aspect map (terrain aspect or azimuth of the solar panel) [decimal degrees]
+#%end
+#%option
+#% type: string
+#% gisprompt: old,cell,raster
+#% key: slope_in
+#% description: Name of the input slope raster map (terrain slope or solar panel inclination) [decimal degrees]
+#%end
+#%option
+#% key: start_time
+#% type: double
+#% label: Start time of interval
+#% description: Use up to 2 decimal places
+#% options: 0-24
+#% required : yes
+#%end
+#%option
+#% key: end_time
+#% type: double
+#% label: End time of interval
+#% description: Use up to 2 decimal places
+#% options: 0-24
+#% required : yes
+#%end
+#%option
+#% key: time_step
+#% type: double
+#% label: Time step for running r.sun [decimal hours]
+#% description: Use up to 2 decimal places
+#% options: 0-24
+#% answer: 1
+#%end
+#%option
+#% key: day
+#% type: integer
+#% description: No. of day of the year
+#% options: 1-365
+#% required : yes
+#%end
+#%option
+#% key: year
+#% type: integer
+#% label: Year used for map registration into temporal dataset or r.timestamp
+#% description: This value is not used in r.sun calcluations
+#% options: 1900-9999
+#% required: yes
+#% answer: 1900
+#%end
+#%option
+#% key: civil_time
+#% type: double
+#% description: Civil time zone value, if none, the time will be local solar time
+#%end
+#%option
+#% key: beam_rad_basename
+#% type: string
+#% label: Base name for output beam irradiance raster maps [Wh.m-2]
+#% description: Underscore and day number are added to the base name for each map
+#%end
+#%option
+#% key: diff_rad_basename
+#% type: string
+#% label: Base name for output diffuse irradiance raster maps [Wh.m-2]
+#% description: Underscore and day number are added to the base name for each map
+#%end
+#%option
+#% key: refl_rad_basename
+#% type: string
+#% label: Base name for output ground reflected irradiance raster maps [Wh.m-2]
+#% description: Underscore and day number are added to the base name for each map
+#%end
+#%option
+#% key: glob_rad_basename
+#% type: string
+#% label: Base name for output global (total) irradiance raster maps [Wh.m-2]
+#% description: Underscore and day number are added to the base name for each map
+#%end
+#%option
+#% key: incidout_basename
+#% type: string
+#% label: Base name for output incidence angle raster maps
+#% description: Underscore and day number are added to the base name for each map
+#%end
+#%option
+#% key: nprocs
+#% type: integer
+#% description: Number of r.sun processes to run in parallel
+#% options: 1-
+#% answer: 1
+#%end
+#%flag
+#% key: t
+#% description: Dataset name is the same as the base name for the output series of maps
+#% label: Register created series of output maps into temporal dataset
+#%end
+#%flag
+#% key: overwrite
+#% description: Allow output files to overwrite existing files
+#%end
+
+
+import os
+import datetime
+import atexit
+from multiprocessing import Process
+
+import grass.script as grass
+import grass.script.core as core
+
+TMP = []
+
+
+def cleanup():
+    if len(TMP):
+        core.info(_("Cleaning %d temporary maps...") % len(TMP))
+    for rast in TMP:
+        grass.run_command('g.remove', rast=rast, quiet=True)
+
+
+def is_grass_7():
+    if core.version()['version'].split('.')[0] == '7':
+        return True
+    return False
+
+
+def create_tmp_map_name(name):
+    return '{mod}{pid}_{map_}_tmp'.format(mod='r_sun_crop',
+                                          pid=os.getpid(),
+                                          map_=name)
+
+
+# add latitude map
+def run_r_sun(elevation, aspect, slope, day, time, beam_rad, diff_rad,
+              refl_rad, glob_rad, incidout, suffix):
+    params = {}
+    if beam_rad:
+        params.update({'beam_rad': beam_rad + suffix})
+    if diff_rad:
+        params.update({'diff_rad': diff_rad + suffix})
+    if refl_rad:
+        params.update({'refl_rad': refl_rad + suffix})
+    if glob_rad:
+        params.update({'glob_rad': glob_rad + suffix})
+    if incidout:
+        params.update({'incidout': incidout + suffix})
+
+    if is_grass_7():
+        grass.run_command('r.sun', elev_in=elevation, asp_in=aspect,
+                          slope_in=slope,
+                          day=day, time=time,
+                          overwrite=core.overwrite(), quiet=True,
+                          **params)
+    else:
+        grass.run_command('r.sun', elevin=elevation, aspin=aspect,
+                          slopein=slope,
+                          day=day, time=time,
+                          overwrite=core.overwrite(), quiet=True,
+                          **params)
+
+
+def set_color_table(rasters):
+    if is_grass_7():
+        grass.run_command('r.colors', map=rasters, col='gyr', quiet=True)
+    else:
+        for rast in rasters:
+            grass.run_command('r.colors', map=rast, col='gyr', quiet=True)
+
+
+def set_time_stamp(raster, time):
+    grass.run_command('r.timestamp', map=raster, date=time, quiet=True)
+
+
+def format_time(time):
+    return '%05.2f' % time
+
+
+def check_time_map_names(basename, mapset, start_time, end_time, time_step):
+    if not basename:
+        return
+    for time in frange(start_time, end_time, time_step):
+        map_ = '%s%s%s' % (basename, '_', format_time(time))
+        if grass.find_file(map_, element='cell', mapset=mapset)['file']:
+            grass.fatal(_("Raster map <%s> already exists. Change the base name or allow overwrite.") % map_)
+
+
+def frange(x, y, step):
+    while x <= y:
+        yield x
+        x += step
+
+
+def format_grass_time(dt):
+    """!Format datetime object to grass timestamps.
+    Copied from temporal framework to use thsi script also in GRASS 6.
+    """
+    # GRASS datetime month names
+    month_names = ["", "jan", "feb", "mar", "apr", "may", "jun",
+                   "jul", "aug", "sep", "oct", "nov", "dec"]
+    return "%.2i %s %.4i %.2i:%.2i:%.2i" % (dt.day, month_names[dt.month],
+                                            dt.year, dt.hour, dt.minute, dt.second)
+
+
+def main():
+    options, flags = grass.parser()
+
+    elevation_input = options['elev_in']
+    aspect_input = options['asp_in']
+    slope_input = options['slope_in']
+
+    beam_rad_basename = options['beam_rad_basename']
+    diff_rad_basename = options['diff_rad_basename']
+    refl_rad_basename = options['refl_rad_basename']
+    glob_rad_basename = options['glob_rad_basename']
+    incidout_basename = options['incidout_basename']
+
+    if not any([beam_rad_basename, diff_rad_basename,
+                refl_rad_basename, glob_rad_basename,
+                incidout_basename]):
+        grass.fatal(_("No output specified."))
+
+    start_time = float(options['start_time'])
+    end_time = float(options['end_time'])
+    time_step = float(options['time_step'])
+    nprocs = int(options['nprocs'])
+    day = int(options['day'])
+    temporal = flags['t']
+    year = int(options['year'])
+
+    if not is_grass_7() and temporal:
+        grass.warning(_("Flag t has effect only in GRASS 7"))
+
+    # check: start < end
+    if start_time > end_time:
+        grass.fatal(_("Start time is after end time."))
+    if time_step >= end_time - start_time:
+        grass.fatal(_("Time step is too big."))
+
+    # here we check all the days
+    if not grass.overwrite():
+        check_time_map_names(beam_rad_basename, grass.gisenv()['MAPSET'],
+                              start_time, end_time, time_step)
+        check_time_map_names(diff_rad_basename, grass.gisenv()['MAPSET'],
+                              start_time, end_time, time_step)
+        check_time_map_names(refl_rad_basename, grass.gisenv()['MAPSET'],
+                              start_time, end_time, time_step)
+        check_time_map_names(glob_rad_basename, grass.gisenv()['MAPSET'],
+                              start_time, end_time, time_step)
+
+    # check for slope/aspect
+    if not aspect_input or not slope_input:
+        params = {}
+        if not aspect_input:
+            aspect_input = create_tmp_map_name('aspect')
+            params.update({'aspect': aspect_input})
+            TMP.append(aspect_input)
+        if not slope_input:
+            slope_input = create_tmp_map_name('slope')
+            params.update({'slope': slope_input})
+            TMP.append(slope_input)
+
+        grass.info(_("Running r.slope.aspect..."))
+        grass.run_command('r.slope.aspect', elevation=elevation_input, quiet=True, **params)
+
+    grass.info(_("Running r.sun in a loop..."))
+    count = 0
+    # Parallel processing
+    proc_list = []
+    proc_count = 0
+    suffixes = []
+    suffixes_all = []
+    times = list(frange(start_time, end_time, time_step))
+    num_times = len(times)
+    core.percent(0, num_times, 1)
+    for time in times:
+        count += 1
+        core.percent(count, num_times, 10)
+
+        suffix = '_' + format_time(time)
+        proc_list.append(Process(target=run_r_sun,
+                                 args=(elevation_input, aspect_input,
+                                       slope_input, day, time,
+                                       beam_rad_basename,
+                                       diff_rad_basename,
+                                       refl_rad_basename,
+                                       glob_rad_basename,
+                                       incidout_basename,
+                                       suffix)))
+
+        proc_list[proc_count].start()
+        proc_count += 1
+        suffixes.append(suffix)
+        suffixes_all.append(suffix)
+
+        if proc_count == nprocs or proc_count == num_times or count == num_times:
+            proc_count = 0
+            exitcodes = 0
+            for proc in proc_list:
+                proc.join()
+                exitcodes += proc.exitcode
+
+            if exitcodes != 0:
+                core.fatal(_("Error while r.sun computation"))
+
+            # Empty process list
+            proc_list = []
+            suffixes = []
+    # FIXME: how percent really works?
+    # core.percent(1, 1, 1)
+
+    # add timestamps either via temporal framework in 7 or r.timestamp in 6.x
+    if is_grass_7() and temporal:
+        core.info(_("Registering created maps into temporal dataset..."))
+        import grass.temporal as tgis
+
+        def registerToTemporal(basename, suffixes, mapset, start_time, time_step, title, desc):
+            maps = ','.join([basename + suf + '@' + mapset for suf in suffixes])
+            tgis.open_new_space_time_dataset(basename, type='strds', temporaltype='absolute',
+                                             title=title, descr=desc,
+                                             semantic='mean', dbif=None, overwrite=grass.overwrite())
+            tgis.register_maps_in_space_time_dataset(
+                type='rast', name=basename, maps=maps, start=start_time, end=None,
+                increment=time_step, dbif=None, interval=False)
+        # Make sure the temporal database exists
+        tgis.init()
+
+        mapset = grass.gisenv()['MAPSET']
+        absolute_time = datetime.datetime(year, 1, 1) + \
+                        datetime.timedelta(days=day - 1) + \
+                        datetime.timedelta(hours=start_time)
+        start = absolute_time.strftime("%Y-%m-%d %H:%M:%S")
+        step = datetime.timedelta(hours=time_step)
+        step = "%d seconds" % step.seconds
+
+        if beam_rad_basename:
+            registerToTemporal(beam_rad_basename, suffixes_all, mapset, start, step,
+                               title="Beam irradiance",
+                               desc="Output beam irradiance raster maps [Wh.m-2]")
+        if diff_rad_basename:
+            registerToTemporal(diff_rad_basename, suffixes_all, mapset, start, step,
+                               title="Diffuse irradiance",
+                               desc="Output diffuse irradiance raster maps [Wh.m-2]")
+        if refl_rad_basename:
+            registerToTemporal(refl_rad_basename, suffixes_all, mapset, start, step,
+                               title="Reflected irradiance",
+                               desc="Output reflected irradiance raster maps [Wh.m-2]")
+        if glob_rad_basename:
+            registerToTemporal(glob_rad_basename, suffixes_all, mapset, start, step,
+                               title="Total irradiance",
+                               desc="Output total irradiance raster maps [Wh.m-2]")
+        if incidout_basename:
+            registerToTemporal(incidout_basename, suffixes_all, mapset, start, step,
+                               title="Incidence angle",
+                               desc="Output incidence angle raster maps")
+
+    else:
+        absolute_time = datetime.datetime(year, 1, 1) + \
+                        datetime.timedelta(days=day - 1)
+        for i, time in enumerate(times):
+            grass_time = format_grass_time(absolute_time + datetime.timedelta(hours=time))
+            if beam_rad_basename:
+                set_time_stamp(beam_rad_basename + suffixes_all[i], time=grass_time)
+            if diff_rad_basename:
+                set_time_stamp(diff_rad_basename + suffixes_all[i], time=grass_time)
+            if refl_rad_basename:
+                set_time_stamp(refl_rad_basename + suffixes_all[i], time=grass_time)
+            if glob_rad_basename:
+                set_time_stamp(glob_rad_basename + suffixes_all[i], time=grass_time)
+            if incidout_basename:
+                set_time_stamp(incidout_basename + suffixes_all[i], time=grass_time)
+
+    if beam_rad_basename:
+        maps = [beam_rad_basename + suf for suf in suffixes_all]
+        set_color_table(maps)
+    if diff_rad_basename:
+        maps = [diff_rad_basename + suf for suf in suffixes_all]
+        set_color_table(maps)
+    if refl_rad_basename:
+        maps = [refl_rad_basename + suf for suf in suffixes_all]
+        set_color_table(maps)
+    if glob_rad_basename:
+        maps = [glob_rad_basename + suf for suf in suffixes_all]
+        set_color_table(maps)
+    if incidout_basename:
+        maps = [incidout_basename + suf for suf in suffixes_all]
+        set_color_table(maps)
+
+
+
+if __name__ == "__main__":
+    atexit.register(cleanup)
+    main()


Property changes on: grass-addons/grass7/raster/r.sun.hourly/r.sun.hourly.py
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass-addons/grass7/raster/r.sun.hourly/test.r.sun.hourly.sh
===================================================================
--- grass-addons/grass7/raster/r.sun.hourly/test.r.sun.hourly.sh	                        (rev 0)
+++ grass-addons/grass7/raster/r.sun.hourly/test.r.sun.hourly.sh	2013-08-28 19:39:20 UTC (rev 57533)
@@ -0,0 +1,125 @@
+#!/bin/sh
+
+############################################################################
+#
+# TEST:      test.r.sun.hourly
+# AUTHOR(S): Vaclav Petras, Anna Petrasova
+# PURPOSE:   This is test for r.sun.hourly module
+# COPYRIGHT: (C) 2013 by the GRASS Development Team
+#
+#                This program is free software under the GNU General Public
+#                License (>=v2). Read the file COPYING that comes with GRASS
+#                for details.
+#
+#############################################################################
+
+# @preprocess step
+# The region setting should work for UTM and LL test locations
+# region could be set to some real values to avoid unable to read fp range warning
+g.region s=30 n=40 w=40 e=60 res=10
+r.mapcalc --o expr="building = 50"
+
+g.region s=0 n=80 w=0 e=120 res=10
+r.mapcalc --o expr="terrain = 10"
+
+r.mapcalc --o expr="terrain = terrain + building"
+
+map_number_separator="_"
+map_number_pattern="[0-9]{2}.[0-9]{2}"
+
+map_basename=reflmap
+decimal_map_basename=reflmap_decimal
+temporal_map_basename=reflmap_temporal
+
+map_names_file=`g.tempfile pid=$$`
+created_map_names_file=`g.tempfile pid=$$`
+
+decimal_map_names_file=`g.tempfile pid=$$`
+decimal_created_map_names_file=`g.tempfile pid=$$`
+
+temporal_dataset_file=`g.tempfile pid=$$`
+temporal_map_names_file=`g.tempfile pid=$$`
+temporal_created_dataset_file=`g.tempfile pid=$$`
+temporal_created_map_names_file=`g.tempfile pid=$$`
+year=2001
+
+cat > "${map_names_file}" << EOF
+${map_basename}_11.50
+${map_basename}_14.50
+${map_basename}_17.50
+EOF
+
+cat > "${decimal_map_names_file}" << EOF
+${decimal_map_basename}_07.00
+${decimal_map_basename}_08.33
+${decimal_map_basename}_09.67
+${decimal_map_basename}_11.00
+EOF
+
+cat > "${temporal_dataset_file}" << EOF
+${temporal_map_basename}@`g.mapset -p`
+EOF
+
+cat > "${temporal_map_names_file}" << EOF
+${temporal_map_basename}_11.50 landsat ${year}-04-10 11:30:00 None
+${temporal_map_basename}_14.50 landsat ${year}-04-10 14:30:00 None
+${temporal_map_basename}_17.50 landsat ${year}-04-10 17:30:00 None
+EOF
+
+# The @test
+
+NAME="Missing ouput parameter test (module should fail)"
+r.sun.hourly elev_in=terrain start_time=11.50 end_time=18.20 time_step=3 day=80
+echo "$NAME: r.sun.hourly returned: $? (expecting 1)"
+
+NAME="Wrong start and end time parameter values test (module should fail)"
+r.sun.hourly elev_in=terrain start_time=11.50 end_time=9.00 time_step=3 day=80 reflrad_basename=${map_basename}
+echo "$NAME: r.sun.hourly returned: $? (expecting 1)"
+
+NAME="Wrong time step parameter value test (module should fail)"
+r.sun.hourly elev_in=terrain start_time=10.60 end_time=11.20 time_step=0.60 day=80 reflrad_basename=${map_basename}
+echo "$NAME: r.sun.hourly returned: $? (expecting 1)"
+
+NAME="Map creation test"
+r.sun.hourly elev_in=terrain start_time=11.50 end_time=20.00 time_step=3 day=80 reflrad_basename=${map_basename}
+
+g.mlist -e type=rast pattern=${map_basename}${map_number_separator}${map_number_pattern} sep=newline > ${created_map_names_file}
+
+diff ${map_names_file} ${created_map_names_file}
+echo "$NAME: Diff returned $? (expecting 0)"
+
+NAME="Map creation test with too much decimal places"
+r.sun.hourly elev_in=terrain start_time=7.0000 end_time=11.0000 time_step=1.3333 day=80 reflrad_basename=${decimal_map_basename}
+
+g.mlist -e type=rast pattern=${decimal_map_basename}${map_number_separator}${map_number_pattern} sep=newline > ${decimal_created_map_names_file}
+
+diff ${decimal_map_names_file} ${decimal_created_map_names_file}
+echo "$NAME: Diff returned $? (expecting 0)"
+
+NAME="Temporal dataset creation test"
+r.sun.hourly -t elev_in=terrain start_time=11.50 end_time=20.00 time_step=3 day=100 year=${year} reflrad_basename=${temporal_map_basename}
+
+t.list type=strds > ${temporal_created_dataset_file}
+
+t.rast.list input=${temporal_map_basename} method=col > ${temporal_created_map_names_file}
+
+diff ${temporal_dataset_file} ${temporal_created_dataset_file}
+echo "$NAME (maps temporal dataset subtest): Diff returned $? (expecting 0)"
+
+diff --ignore-all-space ${temporal_map_names_file} ${temporal_created_map_names_file}
+echo "$NAME (maps sub-test): Diff returned $? (expecting 0)"
+
+NAME="Map already exists test (module should fail)"
+r.sun.hourly elev_in=terrain start_time=11.50 end_time=20.00 time_step=3 day=80 reflrad_basename=${map_basename}
+echo "$NAME: r.sun.hourly returned: $? (expecting 1)"
+
+# clean
+rm ${map_names_file} ${created_map_names_file}
+g.remove rast=`g.mlist -e type=rast pattern=${map_basename}${map_number_separator}${map_number_pattern} sep=,`
+
+rm ${decimal_map_names_file} ${decimal_created_map_names_file}
+g.remove rast=`g.mlist -e type=rast pattern=${decimal_map_basename}${map_number_separator}${map_number_pattern} sep=,`
+
+rm ${temporal_map_names_file} ${temporal_dataset_file} ${temporal_created_dataset_file} ${temporal_created_map_names_file}
+t.remove -rf inputs=${temporal_map_basename}
+


Property changes on: grass-addons/grass7/raster/r.sun.hourly/test.r.sun.hourly.sh
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + text/x-sh
Added: svn:eol-style
   + native



More information about the grass-commit mailing list