def compute(): if options["clouds"]: region_mask = "region_mask" run_command("v.overlay", overwrite=True, ainput=options["region"], binput=options["clouds"], operator="not", output=region_mask) else: region_mask = options["region"] run_command("g.region", overwrite=True, vector=region_mask, align=options["red"]) run_command("r.mask", overwrite=True, vector=region_mask) run_command("i.vi", overwrite=True, red=options["red"], output="ndvi", nir=options["nir"]) p1 = feed_command("r.recode", overwrite=True, input="ndvi", output="ndvi_class", rules="-") p1.stdin.write("""-1:0.1:1 0.1:0.5:2 0.5:1:3""") p1.stdin.close() p1.wait() p2 = feed_command("r.colors", map="ndvi_class", rules="-") p2.stdin.write("""1 grey 2 255 255 0 3 green""") p2.stdin.close() p2.wait() run_command("r.to.vect", flags='sv', overwrite=True, input="ndvi_class", output="ndvi_class", type="area") run_command("v.clean", overwrite=True, input="ndvi_class", output=options["output"], tool="rmarea", threshold=options['threshold'])
def main(): images = options['input'].split(',') output = options['output'] count = len(images) msg = _('Do not forget to set region properly to cover all images.') gscript.warning(msg) offset = 0 offsets = [] parms = {} for n, img in enumerate(images): offsets.append(offset) parms['image%d' % (n + 1)] = img parms['offset%d' % (n + 1)] = offset offset += get_limit(img) + 1 gscript.message(_("Mosaicing %d images...") % count) gscript.mapcalc("$output = " + make_expression(1, count), output=output, **parms) # modify the color table: p = gscript.feed_command('r.colors', map=output, rules='-') for img, offset in zip(images, offsets): print(img, offset) copy_colors(p.stdin, img, offset) p.stdin.close() p.wait() gscript.message(_("Done. Raster map <%s> created.") % output) # write cmd history: gscript.raster_history(output)
def save_map(self): p = grass.feed_command('r.in.ascii', input = '-', output = self.tempmap, quiet = True, overwrite = True) outf = p.stdin outf.write("north: %f\n" % self.wind['n']) outf.write("south: %f\n" % self.wind['s']) outf.write("east: %f\n" % self.wind['e']) outf.write("west: %f\n" % self.wind['w']) outf.write("rows: %d\n" % self.wind['rows']) outf.write("cols: %d\n" % self.wind['cols']) outf.write("null: *\n") for row in range(self.wind['rows']): for col in range(self.wind['cols']): if col > 0: outf.write(" ") val = self.values[row][col] if val and self.changed[row][col]: outf.write("%s" % val) else: outf.write('*') outf.write("\n") outf.close() p.wait() run('g.region', raster = self.inmap) run('r.patch', input = (self.tempmap, self.outmap), output = self.outmap, overwrite = True) run('r.colors', map = self.outmap, rast = self.inmap) run('g.remove', flags = 'f', type = 'raster', name = self.tempmap)
def main(): input = options['input'] maskcats = options['maskcats'] remove = flags['r'] invert = flags['i'] if not remove and not input: grass.fatal(_("Required parameter <input> not set")) #check if input file exists if not grass.find_file(input)['file'] and not remove: grass.fatal(_("<%s> does not exist.") % input) if not 'MASKCATS' in grass.gisenv() and not remove: ## beware: next check is made with != , not with 'is', otherwise: #>>> grass.raster_info("basin_50K")['datatype'] is "CELL" #False # even if: #>>> "CELL" is "CELL" #True if grass.raster_info(input)['datatype'] != "CELL": grass.fatal(_("Raster map %s must be integer for maskcats parameter") % input) mapset = grass.gisenv()['MAPSET'] exists = bool(grass.find_file('MASK', element = 'cell', mapset = mapset)['file']) if remove: if exists: grass.run_command('g.remove', rast = 'MASK') grass.message(_("Raster MASK removed")) else: grass.fatal(_("No existing MASK to remove")) else: if exists: if not grass.overwrite(): grass.fatal(_("MASK already found in current mapset. Delete first or overwrite.")) else: grass.warning(_("MASK already exists and will be overwritten")) p = grass.feed_command('r.reclass', input = input, output = 'MASK', overwrite = True, rules = '-') p.stdin.write("%s = 1" % maskcats) p.stdin.close() p.wait() if invert: global tmp tmp = "r_mask_%d" % os.getpid() grass.run_command('g.rename', rast = ('MASK',tmp), quiet = True) grass.mapcalc("MASK=if(isnull($tmp),1,null())", tmp = tmp) grass.run_command('g.remove', rast = tmp, quiet = True) grass.message(_("Inverted MASK created.")) else: grass.message(_("MASK created.")) grass.message(_("All subsequent raster operations will be limited to MASK area. ") + "Removing or renaming raster file named MASK will " + "restore raster operations to normal")
def main(): table = options['table'] force = flags['f'] if not options['driver'] or not options['database']: # check if DB parameters are set, and if not set them. grass.run_command('db.connect', flags='c', quiet=True) kv = grass.db_connection() if options['database']: database = options['database'] else: database = kv['database'] if options['driver']: driver = options['driver'] else: driver = kv['driver'] # schema needed for PG? if force: grass.message(_("Forcing ...")) # check if table exists if not grass.db_table_exist(table): grass.warning( _("Table <%s> not found in database <%s>") % (table, database)) sys.exit(0) # check if table is used somewhere (connected to vector map) used = grass.db.db_table_in_vector(table) if used: grass.warning( _("Deleting table <%s> which is attached to following map(s):") % table) for vect in used: grass.warning("%s" % vect) if not force: grass.message(_("The table <%s> would be deleted.") % table) grass.message("") grass.message( _("You must use the force flag to actually remove it. Exiting.")) sys.exit(0) p = grass.feed_command('db.execute', input='-', database=database, driver=driver) p.stdin.write(encode("DROP TABLE " + table)) p.stdin.close() p.wait() if p.returncode != 0: grass.fatal(_("Cannot continue (problem deleting table)."))
def main(): map = options['map'] layer = options['layer'] columns = options['columns'] columns = [col.strip() for col in columns.split(',')] # does map exist in CURRENT mapset? mapset = grass.gisenv()['MAPSET'] exists = bool( grass.find_file(map, element='vector', mapset=mapset)['file']) if not exists: grass.fatal(_("Vector map <%s> not found in current mapset") % map) try: f = grass.vector_db(map)[int(layer)] except KeyError: grass.fatal( _("There is no table connected to this map. Run v.db.connect or v.db.addtable first." )) table = f['table'] database = f['database'] driver = f['driver'] column_existing = grass.vector_columns(map, int(layer)).keys() for col in columns: if not col: grass.fatal( _("There is an empty column. Did you leave a trailing comma?")) col_name = col.split(' ')[0].strip() if col_name in column_existing: grass.error( _("Column <%s> is already in the table. Skipping.") % col_name) continue grass.verbose(_("Adding column <%s> to the table") % col_name) p = grass.feed_command('db.execute', input='-', database=database, driver=driver) res = "ALTER TABLE {} ADD COLUMN {}".format(table, col) p.stdin.write(encode(res)) grass.debug(res) p.stdin.close() if p.wait() != 0: grass.fatal(_("Unable to add column <%s>.") % col) # write cmd history: grass.vector_history(map)
def main(): table = options['table'] force = flags['f'] # check if DB parameters are set, and if not set them. grass.run_command('db.connect', flags = 'c') kv = grass.db_connection() database = kv['database'] driver = kv['driver'] # schema needed for PG? if force: grass.message(_("Forcing ...")) # check if table exists nuldev = file(os.devnull, 'w') if not grass.db_table_exist(table, stdout = nuldev, stderr = nuldev): grass.fatal(_("Table <%s> not found in current mapset") % table) # check if table is used somewhere (connected to vector map) used = [] vects = grass.list_strings('vect') for vect in vects: for f in grass.vector_db(vect, stderr = nuldev).itervalues(): if not f: continue if f['table'] == table: used.append(vect) break if used: grass.warning(_("Deleting table <%s> which is attached to following map(s):") % table) for vect in used: grass.message(vect) if not force: grass.message(_("The table <%s> would be deleted.") % table) grass.message("") grass.message(_("You must use the force flag to actually remove it. Exiting.")) sys.exit(0) p = grass.feed_command('db.execute', input = '-', database = database, driver = driver) p.stdin.write("DROP TABLE " + table) p.stdin.close() p.wait() if p.returncode != 0: grass.fatal(_("Cannot continue (problem deleting table)."))
def main(): table = options['table'] force = flags['f'] if not options['driver'] or not options['database']: # check if DB parameters are set, and if not set them. grass.run_command('db.connect', flags='c') kv = grass.db_connection() if options['database']: database = options['database'] else: database = kv['database'] if options['driver']: driver = options['driver'] else: driver = kv['driver'] # schema needed for PG? if force: grass.message(_("Forcing ...")) # check if table exists if not grass.db_table_exist(table): grass.fatal(_("Table <%s> not found in database <%s>") % (table, database)) # check if table is used somewhere (connected to vector map) used = grass.db.db_table_in_vector(table) if used: grass.warning(_("Deleting table <%s> which is attached to following map(s):") % table) for vect in used: grass.warning("%s" % vect) if not force: grass.message(_("The table <%s> would be deleted.") % table) grass.message("") grass.message(_("You must use the force flag to actually remove it. Exiting.")) sys.exit(0) p = grass.feed_command('db.execute', input='-', database=database, driver=driver) p.stdin.write("DROP TABLE " + table) p.stdin.close() p.wait() if p.returncode != 0: grass.fatal(_("Cannot continue (problem deleting table)."))
def main(): map = options['map'] layer = options['layer'] columns = options['columns'] columns = [col.strip() for col in columns.split(',')] # does map exist in CURRENT mapset? mapset = grass.gisenv()['MAPSET'] exists = bool(grass.find_file(map, element='vector', mapset=mapset)['file']) if not exists: grass.fatal(_("Vector map <%s> not found in current mapset") % map) try: f = grass.vector_db(map)[int(layer)] except KeyError: grass.fatal( _("There is no table connected to this map. Run v.db.connect or v.db.addtable first.")) table = f['table'] database = f['database'] driver = f['driver'] column_existing = grass.vector_columns(map, int(layer)).keys() for col in columns: if not col: grass.fatal(_("There is an empty column. Did you leave a trailing comma?")) col_name = col.split(' ')[0].strip() if col_name in column_existing: grass.error(_("Column <%s> is already in the table. Skipping.") % col_name) continue grass.verbose(_("Adding column <%s> to the table") % col_name) p = grass.feed_command('db.execute', input='-', database=database, driver=driver) p.stdin.write("ALTER TABLE %s ADD COLUMN %s" % (table, col)) grass.debug("ALTER TABLE %s ADD COLUMN %s" % (table, col)) p.stdin.close() if p.wait() != 0: grass.fatal(_("Unable to add column <%s>.") % col) # write cmd history: grass.vector_history(map)
def save_map(self): p = grass.feed_command("r.in.ascii", input="-", output=self.tempmap, quiet=True, overwrite=True) outf = p.stdin outf.write(grass.encode("north: %f\n" % self.wind["n"])) outf.write(grass.encode("south: %f\n" % self.wind["s"])) outf.write(grass.encode("east: %f\n" % self.wind["e"])) outf.write(grass.encode("west: %f\n" % self.wind["w"])) outf.write(grass.encode("rows: %d\n" % self.wind["rows"])) outf.write(grass.encode("cols: %d\n" % self.wind["cols"])) outf.write(grass.encode("null: *\n")) for row in range(self.wind["rows"]): for col in range(self.wind["cols"]): if col > 0: outf.write(grass.encode(" ")) val = self.values[row][col] if val and self.changed[row][col]: outf.write(grass.encode("%s" % val)) else: outf.write(grass.encode("*")) outf.write(grass.encode("\n")) outf.close() p.wait() run("g.region", raster=self.inmap) run( "r.patch", input=(self.tempmap, self.outmap), output=self.outmap, overwrite=True, ) run("r.colors", map=self.outmap, rast=self.inmap) run("g.remove", flags="f", type="raster", name=self.tempmap)
def write_stations_snapped(self): """Write out the stations_snapped to a vector.""" types = {'i': 'int', 'f': 'double'} # columns cols = self.stations_snapped_columns cols_dt = [' '.join([i, types[cols[i].dtype.kind]]) for i in cols.keys()] cols_fmt = '|'.join(['%'+cols[i].dtype.kind for i in cols.keys()]) data = np.column_stack(cols.values()) # create vector if needed p = grass.feed_command('v.in.ascii', input='-', x=3, y=4, cat=1, quiet=True, columns=cols_dt, output=self.stations_snapped) np.savetxt(p.stdin, data, delimiter='|', fmt=cols_fmt) p.stdin.close() p.wait() # drop x y columns grun('v.db.dropcolumn', map=self.stations_snapped, columns='x,y') # add other columns cat = grass.vector_info(self.stations_snapped)['attribute_primary_key'] grun('g.copy', vector=self.stations+',stations__tmp', quiet=True) catother = grass.vector_info('stations__tmp')['attribute_primary_key'] grun('v.db.join', map=self.stations_snapped, column=cat, other_table='stations__tmp', other_column=catother, quiet=True) return
def main(): global temp_dist, temp_src input = options["input"] output = options["output"] distances = options["distances"] units = options["units"] zero = flags["z"] tmp = str(os.getpid()) temp_dist = "r.buffer.tmp.%s.dist" % tmp temp_src = "r.buffer.tmp.%s.src" % tmp # check if input file exists if not grass.find_file(input)["file"]: grass.fatal(_("Raster map <%s> not found") % input) scale = scales[units] distances = distances.split(",") distances1 = [scale * float(d) for d in distances] distances2 = [d * d for d in distances1] s = grass.read_command("g.proj", flags="j") kv = grass.parse_key_val(s) if kv["+proj"] == "longlat": metric = "geodesic" else: metric = "squared" grass.run_command("r.grow.distance", input=input, metric=metric, distance=temp_dist, flags="m") if zero: exp = "$temp_src = if($input == 0,null(),1)" else: exp = "$temp_src = if(isnull($input),null(),1)" grass.message(_("Extracting buffers (1/2)...")) grass.mapcalc(exp, temp_src=temp_src, input=input) exp = "$output = if(!isnull($input),$input,%s)" if metric == "squared": for n, dist2 in enumerate(distances2): exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2) else: for n, dist2 in enumerate(distances1): exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2) exp %= "null()" grass.message(_("Extracting buffers (2/2)...")) grass.mapcalc(exp, output=output, input=temp_src, dist=temp_dist) p = grass.feed_command("r.category", map=output, separator=":", rules="-") msg = "1:distances calculated from these locations\n" p.stdin.write(encode(msg)) d0 = "0" for n, d in enumerate(distances): msg = "%d:%s-%s %s\n" % (n + 2, d0, d, units) p.stdin.write(encode(msg)) d0 = d p.stdin.close() p.wait() grass.run_command("r.colors", map=output, color="rainbow") # write cmd history: grass.raster_history(output)
def main(): if not hasNumPy: grass.fatal(_("Required dependency NumPy not found. Exiting.")) sharpen = options['method'] # sharpening algorithm ms1_orig = options['blue'] # blue channel ms2_orig = options['green'] # green channel ms3_orig = options['red'] # red channel pan_orig = options['pan'] # high res pan channel out = options['output'] # prefix for output RGB maps bits = options['bitdepth'] # bit depth of image channels bladjust = flags['l'] # adjust blue channel sproc = flags['s'] # serial processing rescale = flags[ 'r'] # rescale to spread pixel values to entire 0-255 range # Checking bit depth bits = float(bits) if bits < 2 or bits > 30: grass.warning(_("Bit depth is outside acceptable range")) return outb = grass.core.find_file('%s_blue' % out) outg = grass.core.find_file('%s_green' % out) outr = grass.core.find_file('%s_red' % out) if (outb['name'] != '' or outg['name'] != '' or outr['name'] != '') and not grass.overwrite(): grass.warning( _('Maps with selected output prefix names already exist.' ' Delete them or use overwrite flag')) return pid = str(os.getpid()) # convert input image channels to 8 bit for processing ms1 = 'tmp%s_ms1' % pid ms2 = 'tmp%s_ms2' % pid ms3 = 'tmp%s_ms3' % pid pan = 'tmp%s_pan' % pid if rescale == False: if bits == 8: grass.message(_("Using 8bit image channels")) if sproc: # serial processing grass.run_command('g.copy', raster='%s,%s' % (ms1_orig, ms1), quiet=True, overwrite=True) grass.run_command('g.copy', raster='%s,%s' % (ms2_orig, ms2), quiet=True, overwrite=True) grass.run_command('g.copy', raster='%s,%s' % (ms3_orig, ms3), quiet=True, overwrite=True) grass.run_command('g.copy', raster='%s,%s' % (pan_orig, pan), quiet=True, overwrite=True) else: # parallel processing pb = grass.start_command('g.copy', raster='%s,%s' % (ms1_orig, ms1), quiet=True, overwrite=True) pg = grass.start_command('g.copy', raster='%s,%s' % (ms2_orig, ms2), quiet=True, overwrite=True) pr = grass.start_command('g.copy', raster='%s,%s' % (ms3_orig, ms3), quiet=True, overwrite=True) pp = grass.start_command('g.copy', raster='%s,%s' % (pan_orig, pan), quiet=True, overwrite=True) pb.wait() pg.wait() pr.wait() pp.wait() else: grass.message(_("Converting image chanels to 8bit for processing")) maxval = pow(2, bits) - 1 if sproc: # serial processing grass.run_command('r.rescale', input=ms1_orig, from_='0,%f' % maxval, output=ms1, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=ms2_orig, from_='0,%f' % maxval, output=ms2, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=ms3_orig, from_='0,%f' % maxval, output=ms3, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=pan_orig, from_='0,%f' % maxval, output=pan, to='0,255', quiet=True, overwrite=True) else: # parallel processing pb = grass.start_command('r.rescale', input=ms1_orig, from_='0,%f' % maxval, output=ms1, to='0,255', quiet=True, overwrite=True) pg = grass.start_command('r.rescale', input=ms2_orig, from_='0,%f' % maxval, output=ms2, to='0,255', quiet=True, overwrite=True) pr = grass.start_command('r.rescale', input=ms3_orig, from_='0,%f' % maxval, output=ms3, to='0,255', quiet=True, overwrite=True) pp = grass.start_command('r.rescale', input=pan_orig, from_='0,%f' % maxval, output=pan, to='0,255', quiet=True, overwrite=True) pb.wait() pg.wait() pr.wait() pp.wait() else: grass.message(_("Rescaling image chanels to 8bit for processing")) min_ms1 = int(grass.raster_info(ms1_orig)['min']) max_ms1 = int(grass.raster_info(ms1_orig)['max']) min_ms2 = int(grass.raster_info(ms2_orig)['min']) max_ms2 = int(grass.raster_info(ms2_orig)['max']) min_ms3 = int(grass.raster_info(ms3_orig)['min']) max_ms3 = int(grass.raster_info(ms3_orig)['max']) min_pan = int(grass.raster_info(pan_orig)['min']) max_pan = int(grass.raster_info(pan_orig)['max']) maxval = pow(2, bits) - 1 if sproc: # serial processing grass.run_command('r.rescale', input=ms1_orig, from_='%f,%f' % (min_ms1, max_ms1), output=ms1, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=ms2_orig, from_='%f,%f' % (min_ms2, max_ms2), output=ms2, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=ms3_orig, from_='%f,%f' % (min_ms3, max_ms3), output=ms3, to='0,255', quiet=True, overwrite=True) grass.run_command('r.rescale', input=pan_orig, from_='%f,%f' % (min_pan, max_pan), output=pan, to='0,255', quiet=True, overwrite=True) else: # parallel processing pb = grass.start_command('r.rescale', input=ms1_orig, from_='%f,%f' % (min_ms1, max_ms1), output=ms1, to='0,255', quiet=True, overwrite=True) pg = grass.start_command('r.rescale', input=ms2_orig, from_='%f,%f' % (min_ms2, max_ms2), output=ms2, to='0,255', quiet=True, overwrite=True) pr = grass.start_command('r.rescale', input=ms3_orig, from_='%f,%f' % (min_ms3, max_ms3), output=ms3, to='0,255', quiet=True, overwrite=True) pp = grass.start_command('r.rescale', input=pan_orig, from_='%f,%f' % (min_pan, max_pan), output=pan, to='0,255', quiet=True, overwrite=True) pb.wait() pg.wait() pr.wait() pp.wait() # get PAN resolution: kv = grass.raster_info(map=pan) nsres = kv['nsres'] ewres = kv['ewres'] panres = (nsres + ewres) / 2 # clone current region grass.use_temp_region() grass.run_command('g.region', res=panres, align=pan) # Select sharpening method grass.message( _("Performing pan sharpening with hi res pan image: %f" % panres)) if sharpen == "brovey": brovey(pan, ms1, ms2, ms3, out, pid, sproc) elif sharpen == "ihs": ihs(pan, ms1, ms2, ms3, out, pid, sproc) elif sharpen == "pca": pca(pan, ms1, ms2, ms3, out, pid, sproc) # Could add other sharpening algorithms here, e.g. wavelet transformation grass.message( _("Assigning grey equalized color tables to output images...")) # equalized grey scales give best contrast grass.message(_("setting pan-sharpened channels to equalized grey scale")) for ch in ['red', 'green', 'blue']: grass.run_command('r.colors', quiet=True, map="%s_%s" % (out, ch), flags="e", color='grey') # Landsat too blue-ish because panchromatic band less sensitive to blue # light, so output blue channed can be modified if bladjust: grass.message(_("Adjusting blue channel color table...")) blue_colors = ['0 0 0 0\n5% 0 0 0\n67% 255 255 255\n100% 255 255 255'] # these previous colors are way too blue for landsat # blue_colors = ['0 0 0 0\n10% 0 0 0\n20% 200 200 200\n40% 230 230 230\n67% 255 255 255\n100% 255 255 255'] bc = grass.feed_command('r.colors', quiet=True, map="%s_blue" % out, rules="-") bc.stdin.write('\n'.join(blue_colors)) bc.stdin.close() # output notice grass.verbose( _("The following pan-sharpened output maps have been generated:")) for ch in ['red', 'green', 'blue']: grass.verbose(_("%s_%s") % (out, ch)) grass.verbose( _("To visualize output, run: g.region -p raster=%s_red" % out)) grass.verbose(_("d.rgb r=%s_red g=%s_green b=%s_blue" % (out, out, out))) grass.verbose( _("If desired, combine channels into a single RGB map with 'r.composite'." )) grass.verbose( _("Channel colors can be rebalanced using i.colors.enhance.")) # write cmd history: for ch in ['red', 'green', 'blue']: grass.raster_history("%s_%s" % (out, ch)) # create a group with the three outputs #grass.run_command('i.group', group=out, # input="{n}_red,{n}_blue,{n}_green".format(n=out)) # Cleanup grass.message(_("cleaning up temp files")) try: grass.run_command('g.remove', flags="f", type="raster", pattern="tmp%s*" % pid, quiet=True) except: ""
def calculate_lfp(input, output, idcol, id, coords, outlet, layer, outletidcol): prefix = "r_lfp_%d_" % os.getpid() if id: ids = id.split(",") for i in range(0, len(ids)): try: ids[i] = int(ids[i]) except: grass.fatal(_("Invalid ID '%s'") % ids[i]) else: ids = [] if coords: coords = coords.split(",") else: coords = [] # append outlet points to coordinates if outlet: p = grass.pipe_command("v.report", map=outlet, layer=layer, option="coor") for line in p.stdout: line = line.rstrip("\n") if line.startswith("cat|"): colnames = line.split("|") outletid_ind = -1 for i in range(0, len(colnames)): colname = colnames[i] if colname == outletidcol: outletid_ind = i elif colname == "x": x_ind = i elif colname == "y": y_ind = i if outletidcol and outletid_ind == -1: grass.fatal( _("Cannot find column <%s> in vector map <%s>") % (outletidcol, outlet)) continue cols = line.split("|") coords.extend([cols[x_ind], cols[y_ind]]) if outletid_ind >= 0: try: ids.extend([int(cols[outletid_ind])]) except: grass.fatal(_("Invalid ID '%s'") % ids[i]) p.wait() if p.returncode != 0: grass.fatal(_("Cannot read outlet points")) if len(ids) > 0: if len(ids) > len(coords) / 2: grass.fatal(_("Too many IDs")) elif len(ids) < len(coords) / 2: grass.fatal(_("Too few IDs")) assign_id = True else: assign_id = False # create the output vector map try: grass.run_command("v.edit", map=output, tool="create") except CalledModuleError: grass.fatal(_("Cannot create the output vector map")) if assign_id: try: grass.run_command("v.db.addtable", map=output, columns="%s integer" % idcol) except CalledModuleError: grass.fatal(_("Cannot add a table to the output vector map")) for i in range(0, len(coords) / 2): cat = i + 1 coor = "%s,%s" % (coords[2 * i], coords[2 * i + 1]) if assign_id: id = ids[i] grass.message(_("Processing outlet %d at %s...") % (id, coor)) else: grass.message(_("Processing outlet at %s...") % coor) # create the outlet vector map out = prefix + "out" p = grass.feed_command("v.in.ascii", overwrite=True, input="-", output=out, separator=",") p.stdin.write(coor) p.stdin.close() p.wait() if p.returncode != 0: grass.fatal(_("Cannot create the outlet vector map")) # convert the outlet vector map to raster try: grass.run_command("v.to.rast", overwrite=True, input=out, output=out, use="cat", type="point") except CalledModuleError: grass.fatal(_("Cannot convert the outlet vector to raster")) # calculate the downstream flow length flds = prefix + "flds" try: grass.run_command("r.stream.distance", overwrite=True, flags="om", stream_rast=out, direction=input, method="downstream", distance=flds) except CalledModuleError: grass.fatal(_("Cannot calculate the downstream flow length")) # find the longest flow length p = grass.pipe_command("r.info", flags="r", map=flds) max = "" for line in p.stdout: line = line.rstrip("\n") if line.startswith("max="): max = line.split("=")[1] break p.wait() if p.returncode != 0 or max == "": grass.fatal(_("Cannot find the longest flow length")) threshold = float(max) - 0.0005 # find the headwater cells heads = prefix + "heads" try: grass.run_command("r.mapcalc", overwrite=True, expression="%s=if(%s>=%f,1,null())" % (heads, flds, threshold)) except CalledModuleError: grass.fatal(_("Cannot find the headwater cells")) # create the headwater vector map try: grass.run_command("r.to.vect", overwrite=True, input=heads, output=heads, type="point") except CalledModuleError: grass.fatal(_("Cannot create the headwater vector map")) # calculate the longest flow path in vector format path = prefix + "path" try: grass.run_command("r.path", overwrite=True, input=input, vector_path=path, start_points=heads) except CalledModuleError: grass.fatal(_("Cannot create the longest flow path vector map")) # snap the outlet try: grass.run_command("r.to.vect", overwrite=True, input=out, output=out, type="point") except CalledModuleError: grass.fatal(_("Cannot snap the outlet")) # find the coordinates of the snapped outlet p = grass.pipe_command("v.to.db", flags="p", map=out, option="coor") coor = "" for line in p.stdout: line = line.rstrip("\n") if line == "cat|x|y|z": continue cols = line.split("|") coor = "%s,%s" % (cols[1], cols[2]) p.wait() if p.returncode != 0 or coor == "": grass.fatal(_("Cannot find the coordinates of the snapped outlet")) # split the longest flow path at the outlet try: grass.run_command("v.edit", map=path, tool="break", coords=coor) except CalledModuleError: grass.fatal(_("Cannot split the longest flow path at the outlet")) # select the final longest flow path lfp = prefix + "lfp" try: grass.run_command("v.select", overwrite=True, ainput=path, binput=heads, output=lfp) except CalledModuleError: grass.fatal(_("Cannot select the final longest flow path")) lfp2 = lfp + "2" try: grass.run_command("v.category", overwrite=True, input=lfp, output=lfp2, option="del", cat=-1) grass.run_command("v.category", overwrite=True, input=lfp2, output=lfp, option="add", cat=cat, step=0) except CalledModuleError: grass.fatal(_("Cannot add category %d") % cat) # copy the final longest flow path to the output map try: grass.run_command("v.edit", flags="r", map=output, tool="copy", bgmap=lfp, cats=0) except CalledModuleError: grass.fatal(_("Cannot copy the final longest flow path")) if assign_id: try: grass.run_command("v.to.db", map=output, option="cat", columns="cat") grass.run_command("v.db.update", map=output, column=idcol, value=id, where="cat=%d" % cat) except CalledModuleError: grass.fatal(_("Cannot assign ID %d") % id) # remove intermediate outputs grass.run_command("g.remove", flags="f", type="raster,vector", pattern="%s*" % prefix) # write history if supported version = grass.version() if version["revision"] != "exported": # the revision number is available version = int(version["revision"][1:]) else: # some binary distributions don't build from the SVN repository and # revision is not available; use the libgis revision as a fallback in # this case version = int(version["libgis_revision"]) if version >= 70740: # v.support -h added in r70740 grass.run_command("v.support", flags="h", map=output, cmdhist=os.environ["CMDLINE"])
def main(): global tmp, tmp_proj, tmp_gpx, tmp_extr, tmp_vogb format = options['format'] input = options['input'] layer = options['layer'] output = options['output'] type = options['type'] where = options['where'] wpt = flags['w'] rte = flags['r'] trk = flags['t'] nflags = len(filter(None, [wpt, rte, trk])) if nflags > 1: grass.fatal(_("One feature at a time please.")) if nflags < 1: grass.fatal(_("No features requested for export.")) # set some reasonable defaults if not type: if wpt: type = 'point' else: type = 'line' #### check for gpsbabel ### FIXME: may need --help or similar? if not grass.find_program("gpsbabel"): grass.fatal(_("The gpsbabel program was not found, please install it first.\n") + "http://gpsbabel.sourceforge.net") #### check for cs2cs if not grass.find_program("cs2cs"): grass.fatal(_("The cs2cs program was not found, please install it first.\n") + "http://proj.osgeo.org") # check if we will overwrite data if os.path.exists(output) and not grass.overwrite(): grass.fatal(_("Output file already exists.")) #### set temporary files tmp = grass.tempfile() # SQL extract if needed if where: grass.verbose("Extracting data ...") tmp_extr = "tmp_vogb_extr_%d" % os.getpid() ret = grass.run_command('v.extract', input = "$GIS_OPT_INPUT", output = tmp_extr, type = type, layer = layer, where = where, quiet = True) if ret != 0: grass.fatal(_("Error executing SQL query")) kv = grass.vector_info_topo(tmp_extr) if kv['primitives'] == 0: grass.fatal(_("SQL query returned an empty map (no %s features?)") % type) inmap = tmp_extr else: # g.copy "$GIS_OPT_INPUT,tmp_vogb_extr_$$" # to get a copy of DB into local mapset # INMAP="tmp_vogb_extr_$$" inmap = input #### set up projection info # TODO: check if we are already in ll/WGS84. If so skip m.proj step. # TODO: multi layer will probably fail badly due to sed 's/^ 1 /' # output as old GRASS 4 vector ascii and fight with dig_ascii/? # Change to s/^ \([0-9] .*\) /# \1/' ??? mmph. # reproject to lat/lon WGS84 grass.verbose("Reprojecting data ...") re1 = re.compile(r'^\([PLBCFKA]\)') re2 = re.compile(r'^ 1 ') re3 = re.compile(r'\t\([-\.0-9]*\) .*') re4 = re.compile(r'^\([-\.0-9]\)') re5 = re.compile(r'^#') tmp_proj = tmp + ".proj" tf = open(tmp_proj, 'w') p1 = grass.pipe_command('v.out.ascii', input = inmap, format = 'standard') p2 = grass.feed_command('m.proj', input = '-', flags = 'od', quiet = True, stdout = tf) tf.close() lineno = 0 for line in p1.stdout: lineno += 1 if lineno < 11: continue line = re1.sub(r'#\1', line) line = re2.sub(r'# 1 ', line) p2.stdin.write(line) p2.stdin.close() p1.wait() p2.wait() if p1.returncode != 0 or p2.returncode != 0: grass.fatal(_("Error reprojecting data")) tmp_vogb = "tmp_vogb_epsg4326_%d" % os.getpid() p3 = grass.feed_command('v.in.ascii', out = tmp_vogb, format = 'standard', flags = 'n', quiet = True) tf = open(tmp_proj, 'r') for line in tf: line = re3.sub(r' \1', line) line = re4.sub(r' \1', line) line = re5.sub('', line) p3.stdin.write(line) p3.stdin.close() tf.close() p3.wait() if p3.returncode != 0: grass.fatal(_("Error reprojecting data")) # don't v.db.connect directly as source table will be removed with # temporary map in that case. So we make a temp copy of it to work with. kv = vector_db(inmap) if layer in kv: db_params = kv[layer] db_table = db_params['table'] db_key = db_params['key'] db_database = db_params['database'] db_driver = db_params['driver'] ret = grass.run_command('db.copy', from_driver = db_driver, from_database = db_database, from_table = db_table, to_table = tmp_vogb) if ret != 0: grass.fatal(_("Error copying temporary DB")) ret = grass.run_command('v.db.connect', map = tmp_vogb, table = tmp_vogb, quiet = True) if ret != 0: grass.fatal(_("Error reconnecting temporary DB")) # export as GPX using v.out.ogr if trk: linetype = "FORCE_GPX_TRACK=YES" elif rte: linetype = "FORCE_GPX_TRACK=YES" else: linetype = None # BUG: cat is being reported as evelation and attribute output is skipped. # (v.out.ogr DB reading or ->OGR GPX driver bug<- # resolved: see new Create opts at http://www.gdal.org/ogr/drv_gpx.html) # v.out.ogr -> shapefile -> GPX works, but we try to avoid that as it's # lossy. Also that would allow ogr2ogr -a_srs $IN_PROJ -t_srs EPSG:4326 # so skip m.proj pains.. if that is done ogr2ogr -s_srs MUST HAVE +wktext # with PROJ.4 terms or else the +nadgrids will be ignored! best to feed # it IN_PROJ="`g.proj -jf` +wktext" in that case. grass.verbose("Exporting data ...") tmp_gpx = tmp + ".gpx" ret = grass.run_command('v.out.ogr', input = tmp_vogb, dsn = tmp_gpx, type = type, format = 'GPX', lco = linetype, dsco = "GPX_USE_EXTENSIONS=YES", quiet = True) if ret != 0: grass.fatal(_("Error exporting data")) if format == 'gpx': # short circuit, we have what we came for. grass.try_remove(output) os.rename(tmp_gpx, output) grass.verbose("Fast exit.") sys.exit() # run gpsbabel if wpt: gtype = '-w' elif trk: gtype = '-t' elif rte: gtype = '-r' else: gtype = '' grass.verbose("Running GPSBabel ...") ret = grass.call(['gpsbabel', gtype, '-i', 'gpx', '-f', tmp + '.gpx', '-o', format, '-F', output]) if ret != 0: grass.fatal(_("Error running GPSBabel")) grass.verbose("Done.")
def main(): options, flags = grass.parser() xAmap = options["xaraster"] xBmap = options["xbraster"] yAmap = options["yaraster"] yBmap = options["ybraster"] output_basename = options["output"] custom_threshold = options["custom_threshold"] stat_threshold = options["stat_threshold"] Xdelta_name = "deltaX" Ydelta_name = "deltaY" anglemap_name = output_basename + "_angle" anglemap_class = anglemap_name + "_class" magnitudemap_name = output_basename + "_magnitude" changemap_name = output_basename + "_change" # Checking that the input maps exist if not grass.find_file(name=xAmap, element="cell")["file"]: grass.fatal("xaraster map <%s> not found" % xAmap) if not grass.find_file(name=xBmap, element="cell")["file"]: grass.fatal("xbraster map <%s> not found" % xBmap) if not grass.find_file(name=yAmap, element="cell")["file"]: grass.fatal("yaraster map <%s> not found" % yAmap) if not grass.find_file(name=xBmap, element="cell")["file"]: grass.fatal("ybraster map <%s> not found" % yBmap) TMPRAST.append(Xdelta_name) TMPRAST.append(Ydelta_name) # Calculating delta for X and Y bands grass.message(_("Calculating DeltaX and DeltaY")) delta_calculation(Xdelta_name, xBmap, xAmap) delta_calculation(Ydelta_name, yBmap, yAmap) # Calculating angle and magnitude maps grass.message(_("Writing angle map %s") % anglemap_name) angle_calculation(anglemap_name, Xdelta_name, Ydelta_name) grass.message(_("Writing magnitude map %s") % magnitudemap_name) magnitude_calculation(magnitudemap_name, Xdelta_name, Ydelta_name) # Reclassifing angle map to get a map with the four quadrants keys = ["1", "2", "3", "4"] vals = [0, 90, 180, 270, 360] rvals = [(int(vals[i - 1]), int(vals[i]), keys[i - 1], vals[i - 1], vals[i]) for i in range(1, len(vals))] rules = "\n".join(["%3d thru %3d = %s %s-%s" % v for v in rvals]) script.write_command( "r.reclass", input=anglemap_name, output=anglemap_class, rules="-", overwrite=True, stdin=rules.encode(), ) # Generating the change detection map using the given threshold if custom_threshold: threshold = custom_threshold grass.message(_("Threshold is %s") % threshold) grass.message(_("Writing change detection map %s") % changemap_name) # Creating the final map of the change, using a custom threshold change_map_calculation(changemap_name, magnitudemap_name, threshold, anglemap_class) elif stat_threshold: # Getting values of mean and standard dev of magnitude to calculate the change detection criteria (> mean + N*stdev) univar = grass.read_command("r.univar", map=magnitudemap_name, flags="g") found = 0 for line in univar.splitlines(): name, val = line.split("=") if name == "mean": grass.message(_("Mean of magnitude values is: %s") % val) mean = val found += 1 if name == "stddev": grass.message( _("Standard deviation of magnitude values is: %s") % val) stddev = val found += 1 if found != 2: grass.fatal("Couldn't find mean or stddev!") adding_value = float(stat_threshold) * float(stddev) threshold = float(mean) + float(adding_value) grass.message(_("Threshold is %s") % threshold) # Creating the final map of the change, using a statistical threshold change_map_calculation(changemap_name, magnitudemap_name, threshold, anglemap_class) else: grass.message( _("No threshold given, only angle and magnitude maps have been created" )) # anglemap_class: set colors iva_colors = "1 217 255 0\n2 10 214 10\n3 75 173 255\n4 139 105 20\nnv 255 255 255\ndefault 255 255 255" p = grass.feed_command("r.colors", map=anglemap_class, rules="-") p.stdin.write(iva_colors.encode()) p.stdin.close() # anglemap_class: set categories rules = [ "1:moisture reduction", "2:chlorophyll increase", "3:moisture increase", "4:bare soil increase", ] p = grass.feed_command("r.category", map=anglemap_class, rules="-", separator=":") p.stdin.write(("\n".join(rules)).encode()) p.stdin.close() return 0
def main(): """Do the main processing """ # Parse input options: patch_map = options['input'] patches = patch_map.split('@')[0] patches_mapset = patch_map.split('@')[1] if len( patch_map.split('@')) > 1 else None pop_proxy = options['pop_proxy'] layer = options['layer'] costs = options['costs'] cutoff = float(options['cutoff']) border_dist = int(options['border_dist']) conefor_dir = options['conefor_dir'] memory = int(options['memory']) # Parse output options: prefix = options['prefix'] edge_map = '{}_edges'.format(prefix) vertex_map = '{}_vertices'.format(prefix) shortest_paths = '{}_shortest_paths'.format(prefix) # Parse flags: p_flag = flags['p'] t_flag = flags['t'] r_flag = flags['r'] dist_flags = 'kn' if flags['k'] else 'n' lin_cat = 1 zero_dist = None folder = grass.tempdir() if not os.path.exists(folder): os.makedirs(folder) # Setup counter for progress message counter = 0 # Check if location is lat/lon (only in lat/lon geodesic distance # measuring is supported) if grass.locn_is_latlong(): grass.verbose("Location is lat/lon: Geodesic distance \ measure is used") # Check if prefix is legal GRASS name if not grass.legal_name(prefix): grass.fatal('{} is not a legal name for GRASS \ maps.'.format(prefix)) if prefix[0].isdigit(): grass.fatal('Tables names starting with a digit are not SQL \ compliant.'.format(prefix)) # Check if output maps not already exists or could be overwritten for output in [edge_map, vertex_map, shortest_paths]: if grass.db.db_table_exist(output) and not grass.overwrite(): grass.fatal('Vector map <{}> already exists'.format(output)) # Check if input has required attributes in_db_connection = grass.vector.vector_db(patch_map) if not int(layer) in in_db_connection.keys(): grass.fatal('No attribute table connected vector map {} at \ layer {}.'.format(patches, layer)) #Check if cat column exists pcols = grass.vector.vector_columns(patch_map, layer=layer) #Check if cat column exists if not 'cat' in pcols.keys(): grass.fatal('Cannot find the reqired column cat in vector map \ {}.'.format(patches)) #Check if pop_proxy column exists if not pop_proxy in pcols.keys(): grass.fatal('Cannot find column {} in vector map \ {}'.format(pop_proxy, patches)) #Check if pop_proxy column is numeric type if not pcols[pop_proxy]['type'] in ['INTEGER', 'REAL', 'DOUBLE PRECISION']: grass.fatal('Column {} is of type {}. Only numeric types \ (integer or double precision) \ allowed!'.format(pop_proxy, pcols[pop_proxy]['type'])) #Check if pop_proxy column does not contain values <= 0 pop_vals = np.fromstring(grass.read_command('v.db.select', flags='c', map=patches, columns=pop_proxy, nv=-9999).rstrip('\n'), dtype=float, sep='\n') if np.min(pop_vals) <= 0: grass.fatal('Column {} contains values <= 0 or NULL. Neither \ values <= 0 nor NULL allowed!}'.format(pop_proxy)) ############################################## # Use pygrass region instead of grass.parse_command !?! start_reg = grass.parse_command('g.region', flags='ugp') max_n = start_reg['n'] min_s = start_reg['s'] max_e = start_reg['e'] min_w = start_reg['w'] # cost_nsres = reg['nsres'] # cost_ewres = reg['ewres'] # Rasterize patches # http://www.gdal.org/gdal_tutorial.html # http://geoinformaticstutorial.blogspot.no/2012/11/convert- # shapefile-to-raster-with-gdal.html if t_flag: # Rasterize patches with "all-touched" mode using GDAL # Read region-settings (not needed canuse max_n, min_s, max_e, # min_w nsres, ewres... prast = os.path.join(folder, 'patches_rast.tif') # Check if GDAL-GRASS plugin is installed if ogr.GetDriverByName('GRASS'): #With GDAL-GRASS plugin #Locate file for patch vector map pfile = grass.parse_command('g.findfile', element='vector', file=patches, mapset=patches_mapset)['file'] pfile = os.path.join(pfile, 'head') else: # Without GDAL-GRASS-plugin grass.warning("Cannot find GDAL-GRASS plugin. Consider \ installing it in order to save time for \ all-touched rasterisation") pfile = os.path.join(folder, 'patches_vect.gpkg') # Export patch vector map to temp-file in a GDAL-readable # format (shp) grass.run_command('v.out.ogr', flags='m', quiet=True, input=patch_map, type='area', layer=layer, output=pfile, lco='GEOMETRY_NAME=geom') # Rasterize vector map with all-touched option os.system('gdal_rasterize -l {} -at -tr {} {} \ -te {} {} {} {} -ot Uint32 -a cat \ {} {} -q'.format(patches, start_reg['ewres'], start_reg['nsres'], start_reg['w'], start_reg['s'], start_reg['e'], start_reg['n'], pfile, prast)) if not ogr.GetDriverByName('GRASS'): # Remove vector temp-file os.remove(os.path.join(folder, 'patches_vect.gpkg')) # Import rasterized patches grass.run_command('r.external', flags='o', quiet=True, input=prast, output='{}_patches_pol'.format(TMP_PREFIX)) else: # Simple rasterisation (only area) # in G 7.6 also with support for 'centroid' if float(grass.version()['version'][:3]) >= 7.6: conv_types = ['area', 'centroid'] else: conv_types = ['area'] grass.run_command('v.to.rast', quiet=True, input=patches, use='cat', type=conv_types, output='{}_patches_pol'.format(TMP_PREFIX)) # Extract boundaries from patch raster map grass.run_command('r.mapcalc', expression='{p}_patches_boundary=if(\ {p}_patches_pol,\ if((\ (isnull({p}_patches_pol[-1,0])||| \ {p}_patches_pol[-1,0]!={p}_patches_pol)||| \ (isnull({p}_patches_pol[0,1])||| \ {p}_patches_pol[0,1]!={p}_patches_pol)||| \ (isnull({p}_patches_pol[1,0])||| \ {p}_patches_pol[1,0]!={p}_patches_pol)||| \ (isnull({p}_patches_pol[0,-1])||| \ {p}_patches_pol[0,-1]!={p}_patches_pol)), \ {p}_patches_pol,null()), null())'.format(p=TMP_PREFIX), quiet=True) rasterized_cats = grass.read_command( 'r.category', separator='newline', map='{p}_patches_boundary'.format(p=TMP_PREFIX)).replace( '\t', '').strip('\n') rasterized_cats = list( map(int, set([x for x in rasterized_cats.split('\n') if x != '']))) #Init output vector maps if they are requested by user network = VectorTopo(edge_map) network_columns = [(u'cat', 'INTEGER PRIMARY KEY'), (u'from_p', 'INTEGER'), (u'to_p', 'INTEGER'), (u'min_dist', 'DOUBLE PRECISION'), (u'dist', 'DOUBLE PRECISION'), (u'max_dist', 'DOUBLE PRECISION')] network.open('w', tab_name=edge_map, tab_cols=network_columns) vertex = VectorTopo(vertex_map) vertex_columns = [ (u'cat', 'INTEGER PRIMARY KEY'), (pop_proxy, 'DOUBLE PRECISION'), ] vertex.open('w', tab_name=vertex_map, tab_cols=vertex_columns) if p_flag: # Init cost paths file for start-patch grass.run_command('v.edit', quiet=True, map=shortest_paths, tool='create') grass.run_command('v.db.addtable', quiet=True, map=shortest_paths, columns="cat integer,\ from_p integer,\ to_p integer,\ dist_min double precision,\ dist double precision,\ dist_max double precision") start_region_bbox = Bbox(north=float(max_n), south=float(min_s), east=float(max_e), west=float(min_w)) vpatches = VectorTopo(patches, mapset=patches_mapset) vpatches.open('r', layer=int(layer)) ###Loop through patches vpatch_ids = np.array(vpatches.features_to_wkb_list( feature_type="centroid", bbox=start_region_bbox), dtype=[('vid', 'uint32'), ('cat', 'uint32'), ('geom', '|S10')]) cats = set(vpatch_ids['cat']) n_cats = len(cats) if n_cats < len(vpatch_ids['cat']): grass.verbose('At least one MultiPolygon found in patch map.\n \ Using average coordinates of the centroids for \ visual representation of the patch.') for cat in cats: if cat not in rasterized_cats: grass.warning('Patch {} has not been rasterized and will \ therefore not be treated as part of the \ network. Consider using t-flag or change \ resolution.'.format(cat)) continue grass.verbose("Calculating connectivity-distances for patch \ number {}".format(cat)) # Filter from_vpatch = vpatch_ids[vpatch_ids['cat'] == cat] # Get patch ID if from_vpatch['vid'].size == 1: from_centroid = Centroid(v_id=int(from_vpatch['vid']), c_mapinfo=vpatches.c_mapinfo) from_x = from_centroid.x from_y = from_centroid.y # Get centroid if not from_centroid: continue else: xcoords = [] ycoords = [] for f_p in from_vpatch['vid']: from_centroid = Centroid(v_id=int(f_p), c_mapinfo=vpatches.c_mapinfo) xcoords.append(from_centroid.x) ycoords.append(from_centroid.y) # Get centroid if not from_centroid: continue from_x = np.average(xcoords) from_y = np.average(ycoords) # Get BoundingBox from_bbox = grass.parse_command('v.db.select', map=patch_map, flags='r', where='cat={}'.format(cat)) attr_filter = vpatches.table.filters.select(pop_proxy) attr_filter = attr_filter.where("cat={}".format(cat)) proxy_val = vpatches.table.execute().fetchone() # Prepare start patch start_patch = '{}_patch_{}'.format(TMP_PREFIX, cat) reclass_rule = grass.encode('{} = 1\n* = NULL'.format(cat)) recl = grass.feed_command( 'r.reclass', quiet=True, input='{}_patches_boundary'.format(TMP_PREFIX), output=start_patch, rules='-') recl.stdin.write(reclass_rule) recl.stdin.close() recl.wait() # Check if patch was rasterised (patches smaller raster resolution and close to larger patches may not be rasterised) #start_check = grass.parse_command('r.info', flags='r', map=start_patch) #start_check = grass.parse_command('r.univar', flags='g', map=start_patch) #print(start_check) """if start_check['min'] != '1': grass.warning('Patch {} has not been rasterized and will \ therefore not be treated as part of the \ network. Consider using t-flag or change \ resolution.'.format(cat)) grass.run_command('g.remove', flags='f', vector=start_patch, raster=start_patch, quiet=True) grass.del_temp_region() continue""" # Prepare stop patches ############################################ reg = grass.parse_command('g.region', flags='ug', quiet=True, raster=start_patch, n=float(from_bbox['n']) + float(cutoff), s=float(from_bbox['s']) - float(cutoff), e=float(from_bbox['e']) + float(cutoff), w=float(from_bbox['w']) - float(cutoff), align='{}_patches_pol'.format(TMP_PREFIX)) north = reg['n'] if max_n > reg['n'] else max_n south = reg['s'] if min_s < reg['s'] else min_s east = reg['e'] if max_e < reg['e'] else max_e west = reg['w'] if min_w > reg['w'] else min_w # Set region to patch search radius grass.use_temp_region() grass.run_command('g.region', quiet=True, n=north, s=south, e=east, w=west, align='{}_patches_pol'.format(TMP_PREFIX)) # Create buffer around start-patch as a mask # for cost distance analysis grass.run_command('r.buffer', quiet=True, input=start_patch, output='MASK', distances=cutoff) grass.run_command('r.mapcalc', quiet=True, expression='{pf}_patch_{p}_neighbours_contur=\ if({pf}_patches_boundary=={p},\ null(),\ {pf}_patches_boundary)'.format( pf=TMP_PREFIX, p=cat)) grass.run_command('r.mask', flags='r', quiet=True) # Calculate cost distance cost_distance_map = '{}_patch_{}_cost_dist'.format(prefix, cat) grass.run_command('r.cost', flags=dist_flags, quiet=True, overwrite=True, input=costs, output=cost_distance_map, start_rast=start_patch, memory=memory) #grass.run_command('g.region', flags='up') # grass.raster.raster_history(cost_distance_map) cdhist = History(cost_distance_map) cdhist.clear() cdhist.creator = os.environ['USER'] cdhist.write() # History object cannot modify description grass.run_command('r.support', map=cost_distance_map, description='Generated by r.connectivity.distance', history=os.environ['CMDLINE']) # Export distance at boundaries maps = '{0}_patch_{1}_neighbours_contur,{2}_patch_{1}_cost_dist' maps = maps.format(TMP_PREFIX, cat, prefix), connections = grass.encode( grass.read_command('r.stats', flags='1ng', quiet=True, input=maps, separator=';').rstrip('\n')) if connections: con_array = np.genfromtxt(BytesIO(connections), delimiter=';', dtype=None, names=['x', 'y', 'cat', 'dist']) else: grass.warning('No connections for patch {}'.format(cat)) # Write centroid to vertex map vertex.write(Point(from_x, from_y), cat=int(cat), attrs=proxy_val) vertex.table.conn.commit() # Remove temporary map data grass.run_command('g.remove', quiet=True, flags='f', type=['raster', 'vector'], pattern="{}*{}*".format(TMP_PREFIX, cat)) grass.del_temp_region() continue #Find closest points on neigbour patches to_cats = set(np.atleast_1d(con_array['cat'])) to_coords = [] for to_cat in to_cats: connection = con_array[con_array['cat'] == to_cat] connection.sort(order=['dist']) pixel = border_dist if len( connection) > border_dist else len(connection) - 1 # closest_points_x = connection['x'][pixel] # closest_points_y = connection['y'][pixel] closest_points_to_cat = to_cat closest_points_min_dist = connection['dist'][0] closest_points_dist = connection['dist'][pixel] closest_points_max_dist = connection['dist'][-1] to_patch_ids = vpatch_ids[vpatch_ids['cat'] == int(to_cat)]['vid'] if len(to_patch_ids) == 1: to_centroid = Centroid(v_id=to_patch_ids, c_mapinfo=vpatches.c_mapinfo) to_x = to_centroid.x to_y = to_centroid.y elif len(to_patch_ids) >= 1: xcoords = [] ycoords = [] for t_p in to_patch_ids: to_centroid = Centroid(v_id=int(t_p), c_mapinfo=vpatches.c_mapinfo) xcoords.append(to_centroid.x) ycoords.append(to_centroid.y) # Get centroid if not to_centroid: continue to_x = np.average(xcoords) to_y = np.average(ycoords) to_coords.append('{},{},{},{},{},{}'.format( connection['x'][0], connection['y'][0], to_cat, closest_points_min_dist, closest_points_dist, closest_points_max_dist)) #Save edges to network dataset if closest_points_dist <= 0: zero_dist = 1 # Write data to network network.write(Line([(from_x, from_y), (to_x, to_y)]), cat=lin_cat, attrs=( cat, int(closest_points_to_cat), closest_points_min_dist, closest_points_dist, closest_points_max_dist, )) network.table.conn.commit() lin_cat = lin_cat + 1 # Save closest points and shortest paths through cost raster as # vector map (r.drain limited to 1024 points) if requested if p_flag: grass.verbose('Extracting shortest paths for patch number \ {}...'.format(cat)) points_n = len(to_cats) tiles = int(points_n / 1024.0) rest = points_n % 1024 if not rest == 0: tiles = tiles + 1 tile_n = 0 while tile_n < tiles: tile_n = tile_n + 1 #Import closest points for start-patch in 1000er blocks sp = grass.feed_command('v.in.ascii', flags='nr', overwrite=True, quiet=True, input='-', stderr=subprocess.PIPE, output="{}_{}_cp".format( TMP_PREFIX, cat), separator=",", columns="x double precision,\ y double precision,\ to_p integer,\ dist_min double precision,\ dist double precision,\ dist_max double precision") sp.stdin.write(grass.encode("\n".join(to_coords))) sp.stdin.close() sp.wait() # Extract shortest paths for start-patch in chunks of # 1024 points cost_paths = "{}_{}_cost_paths".format(TMP_PREFIX, cat) start_points = "{}_{}_cp".format(TMP_PREFIX, cat) grass.run_command('r.drain', overwrite=True, quiet=True, input=cost_distance_map, output=cost_paths, drain=cost_paths, start_points=start_points) grass.run_command('v.db.addtable', map=cost_paths, quiet=True, columns="cat integer,\ from_p integer,\ to_p integer,\ dist_min double precision,\ dist double precision,\ dist_max double precision") grass.run_command('v.db.update', map=cost_paths, column='from_p', value=cat, quiet=True) grass.run_command('v.distance', quiet=True, from_=cost_paths, to=start_points, upload='to_attr', column='to_p', to_column='to_p') grass.run_command('v.db.join', quiet=True, map=cost_paths, column='to_p', other_column='to_p', other_table=start_points, subset_columns='dist_min,dist,dist_max') #grass.run_command('v.info', flags='c', # map=cost_paths) grass.run_command('v.patch', flags='ae', overwrite=True, quiet=True, input=cost_paths, output=shortest_paths) # Remove temporary map data grass.run_command('g.remove', quiet=True, flags='f', type=['raster', 'vector'], pattern="{}*{}*".format(TMP_PREFIX, cat)) # Remove temporary map data for patch if r_flag: grass.run_command('g.remove', flags='f', type='raster', name=cost_distance_map, quiet=True) vertex.write(Point(from_x, from_y), cat=int(cat), attrs=proxy_val) vertex.table.conn.commit() # Print progress message grass.percent(i=int((float(counter) / n_cats) * 100), n=100, s=3) # Update counter for progress message counter = counter + 1 if zero_dist: grass.warning('Some patches are directly adjacent to others. \ Minimum distance set to 0.0000000001') # Close vector maps and build topology network.close() vertex.close() # Add vertex attributes # grass.run_command('v.db.addtable', map=vertex_map) # grass.run_command('v.db.join', map=vertex_map, column='cat', # other_table=in_db_connection[int(layer)]['table'], # other_column='cat', subset_columns=pop_proxy, # quiet=True) # Add history and meta data to produced maps grass.run_command('v.support', flags='h', map=edge_map, person=os.environ['USER'], cmdhist=os.environ['CMDLINE']) grass.run_command('v.support', flags='h', map=vertex_map, person=os.environ['USER'], cmdhist=os.environ['CMDLINE']) if p_flag: grass.run_command('v.support', flags='h', map=shortest_paths, person=os.environ['USER'], cmdhist=os.environ['CMDLINE']) # Output also Conefor files if requested if conefor_dir: query = """SELECT p_from, p_to, avg(dist) FROM (SELECT CASE WHEN from_p > to_p THEN to_p ELSE from_p END AS p_from, CASE WHEN from_p > to_p THEN from_p ELSE to_p END AS p_to, dist FROM {}) AS x GROUP BY p_from, p_to""".format(edge_map) with open(os.path.join(conefor_dir, 'undirected_connection_file'), 'w') as edges: edges.write( grass.read_command('db.select', sql=query, separator=' ')) with open(os.path.join(conefor_dir, 'directed_connection_file'), 'w') as edges: edges.write( grass.read_command('v.db.select', map=edge_map, separator=' ', flags='c')) with open(os.path.join(conefor_dir, 'node_file'), 'w') as nodes: nodes.write( grass.read_command('v.db.select', map=vertex_map, separator=' ', flags='c'))
def main(): global temp_dist, temp_src input = options['input'] output = options['output'] distances = options['distances'] units = options['units'] zero = flags['z'] tmp = str(os.getpid()) temp_dist = "r.buffer.tmp.%s.dist" % tmp temp_src = "r.buffer.tmp.%s.src" % tmp # check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) scale = scales[units] distances = distances.split(',') distances1 = [scale * float(d) for d in distances] distances2 = [d * d for d in distances1] s = grass.read_command("g.proj", flags='j') kv = grass.parse_key_val(s) if kv['+proj'] == 'longlat': metric = 'geodesic' else: metric = 'squared' grass.run_command('r.grow.distance', input=input, metric=metric, distance=temp_dist, flags='m') if zero: exp = "$temp_src = if($input == 0,null(),1)" else: exp = "$temp_src = if(isnull($input),null(),1)" grass.message(_("Extracting buffers (1/2)...")) grass.mapcalc(exp, temp_src=temp_src, input=input) exp = "$output = if(!isnull($input),$input,%s)" if metric == 'squared': for n, dist2 in enumerate(distances2): exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2) else: for n, dist2 in enumerate(distances1): exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2) exp %= "null()" grass.message(_("Extracting buffers (2/2)...")) grass.mapcalc(exp, output=output, input=temp_src, dist=temp_dist) p = grass.feed_command('r.category', map=output, separator=':', rules='-') msg = "1:distances calculated from these locations\n" p.stdin.write(encode(msg)) d0 = "0" for n, d in enumerate(distances): msg = "%d:%s-%s %s\n" % (n + 2, d0, d, units) p.stdin.write(encode(msg)) d0 = d p.stdin.close() p.wait() grass.run_command('r.colors', map=output, color='rainbow') # write cmd history: grass.raster_history(output)
def main(): raster = options["raster"] maskcats = options["maskcats"] vector = options["vector"] layer = options["layer"] cats = options["cats"] where = options["where"] remove = flags["r"] invert = flags["i"] if not remove and not raster and not vector: grass.fatal( _("Either parameter <raster> or parameter <vector> is required")) mapset = grass.gisenv()["MAPSET"] exists = bool( grass.find_file("MASK", element="cell", mapset=mapset)["file"]) if remove: # -> remove if exists: if sys.platform == "win32": grass.run_command("g.remove", flags="if", quiet=True, type="raster", name="MASK") else: grass.run_command("g.remove", flags="f", quiet=True, type="raster", name="MASK") grass.message(_("Raster MASK removed")) else: grass.fatal(_("No existing MASK to remove")) else: # -> create if exists: if not grass.overwrite(): grass.fatal( _("MASK already found in current mapset. Delete first or overwrite." )) else: grass.warning(_("MASK already exists and will be overwritten")) grass.run_command("g.remove", flags="f", quiet=True, type="raster", name="MASK") if raster: # check if input raster exists if not grass.find_file(raster)["file"]: grass.fatal(_("Raster map <%s> not found") % raster) if maskcats != "*" and not remove: if grass.raster_info(raster)["datatype"] != "CELL": grass.fatal( _("The raster map <%s> must be integer (CELL type) " " in order to use the 'maskcats' parameter") % raster) p = grass.feed_command("r.reclass", input=raster, output="MASK", overwrite=True, rules="-") res = "%s = 1" % maskcats p.stdin.write(encode(res)) p.stdin.close() p.wait() elif vector: vector_name = grass.find_file(vector, "vector")["fullname"] if not vector_name: grass.fatal(_("Vector map <%s> not found") % vector) # parser bug? if len(cats) == 0: cats = None if len(where) == 0: where = None if grass.vector_info_topo(vector_name)["areas"] < 1: grass.warning( _("No area found in vector map <%s>. " "Creating a convex hull for MASK.") % vector_name) global tmp_hull tmp_hull = "tmp_hull_%d" % os.getpid() to_rast_input = tmp_hull # force 'flat' convex hull for 3D vector maps try: grass.run_command( "v.hull", flags="f", quiet=True, input=vector_name, output=tmp_hull, layer=layer, cats=cats, where=where, ) except CalledModuleError: grass.fatal( _("Unable to create a convex hull for vector map <%s>") % vector_name) else: to_rast_input = vector_name env = os.environ.copy() if grass.verbosity() > 1: env["GRASS_VERBOSE"] = "1" grass.run_command( "v.to.rast", input=to_rast_input, layer=layer, output="MASK", use="val", val="1", type="area", cats=cats, where=where, env=env, ) if invert: global tmp tmp = "r_mask_%d" % os.getpid() grass.run_command("g.rename", raster=("MASK", tmp), quiet=True) grass.message(_("Creating inverted raster MASK...")) grass.mapcalc("MASK = if(isnull($tmp), 1, null())", tmp=tmp) grass.verbose(_("Inverted raster MASK created")) else: grass.verbose(_("Raster MASK created")) grass.message( _("All subsequent raster operations will be limited to " "the MASK area. Removing or renaming raster map named " "'MASK' will restore raster operations to normal."))
def main(): input = options['input'] output = options['output'] altitude = options['altitude'] azimuth = options['azimuth'] zmult = options['zmult'] scale = float(options['scale']) units = options['units'] verbose_level = os.getenv('GRASS_VERBOSE') if verbose_level is None: verbose_level = 2 if not grass.find_file(input)['file']: grass.fatal(_("Raster map <%s> not found") % input) if input == output: grass.fatal(_("Input elevation map and output relief map must have different names")) # LatLong locations only: if units == 'meters': # scale=111120 scale *= 1852 * 60 # LatLong locations only: if units == 'feet': # scale=364567.2 scale *= 6076.12 * 60 #correct azimuth to East (GRASS convention): # this seems to be backwards, but in fact it works so leave it. az = float(azimuth) - 90 t = string.Template( r'''eval( \ x=($zmult*$input[-1,-1] + 2*$zmult*$input[0,-1] + $zmult*$input[1,-1] - \ $zmult*$input[-1,1] - 2*$zmult*$input[0,1] - $zmult*$input[1,1])/(8.*ewres()*$scale), \ y=($zmult*$input[-1,-1] + 2*$zmult*$input[-1,0] + $zmult*$input[-1,1] - \ $zmult*$input[1,-1] - 2*$zmult*$input[1,0] - $zmult*$input[1,1])/(8.*nsres()*$scale), \ slope=90.-atan(sqrt(x*x + y*y)), \ a=round(atan(x,y)), \ a=if(isnull(a),1,a), \ aspect=if(x!=0||y!=0,if(a,a,360.)), \ cang = sin($altitude)*sin(slope) + cos($altitude)*cos(slope) * cos($az-aspect) \ ) $output = if(isnull(cang), null(), 100.*cang)''') expr = t.substitute(altitude = altitude, az = az, input = input, output = output, scale = scale, zmult = zmult) p = grass.feed_command('r.mapcalc') p.stdin.write(expr) p.stdin.close() if p.wait() != 0: grass.fatal(_("In calculation, script aborted.")) if verbose_level < 3: grass.run_command('r.colors', map = output, color = 'grey', quiet = True) else: grass.run_command('r.colors', map = output, color = 'grey') # record metadata grass.run_command('r.support', map = output, title = 'Shaded relief of "%s"' % input, history = '') grass.run_command('r.support', map = output, history = "r.shaded.relief settings:") t = string.Template("altitude=$altitude azimuth=$azimuth zmult=$zmult scale=$scale") parms = dict(altitude = altitude, azimuth = azimuth, zmult = zmult, scale = options['scale']) grass.run_command('r.support', map = output, history = t.substitute(parms)) if units: grass.run_command('r.support', map = output, history = " units=%s (adjusted scale=%s)" % (units, scale)) # write cmd history: grass.raster_history(output)
def main(): raster = options['raster'] maskcats = options['maskcats'] vector = options['vector'] layer = options['layer'] cats = options['cats'] where = options['where'] remove = flags['r'] invert = flags['i'] if not remove and not raster and not vector: grass.fatal(_("Either parameter <raster> ot parameter <vector> is required")) mapset = grass.gisenv()['MAPSET'] exists = bool(grass.find_file('MASK', element='cell', mapset=mapset)['file']) if remove: # -> remove if exists: if sys.platform == 'win32': grass.run_command('g.remove', flags='if', quiet=True, type='raster', name='MASK') else: grass.run_command('g.remove', flags='f', quiet=True, type='raster', name='MASK') grass.message(_("Raster MASK removed")) else: grass.fatal(_("No existing MASK to remove")) else: # -> create if exists: if not grass.overwrite(): grass.fatal(_("MASK already found in current mapset. Delete first or overwrite.")) else: grass.warning(_("MASK already exists and will be overwritten")) grass.run_command('g.remove', flags='f', quiet=True, type='raster', name='MASK') if raster: # check if input raster exists if not grass.find_file(raster)['file']: grass.fatal(_("Raster map <%s> not found") % raster) if maskcats != '*' and not remove: if grass.raster_info(raster)['datatype'] != "CELL": grass.fatal(_("The raster map <%s> must be integer (CELL type) " " in order to use the 'maskcats' parameter") % raster) p = grass.feed_command( 'r.reclass', input=raster, output='MASK', overwrite=True, rules='-') p.stdin.write("%s = 1" % maskcats) p.stdin.close() p.wait() elif vector: vector_name = grass.find_file(vector, 'vector')['fullname'] if not vector_name: grass.fatal(_("Vector map <%s> not found") % vector) # parser bug? if len(cats) == 0: cats = None if len(where) == 0: where = None if grass.vector_info_topo(vector_name)['areas'] < 1: grass.warning(_("No area found in vector map <%s>. " "Creating a convex hull for MASK.") % vector_name) global tmp_hull tmp_hull = "tmp_hull_%d" % os.getpid() to_rast_input = tmp_hull # force 'flat' convex hull for 3D vector maps try: grass.run_command('v.hull', flags='f', quiet=True, input=vector_name, output=tmp_hull, layer=layer, cats=cats, where=where) except CalledModuleError: grass.fatal( _("Unable to create a convex hull for vector map <%s>") % vector_name) else: to_rast_input = vector_name env = os.environ.copy() if grass.verbosity() > 1: env['GRASS_VERBOSE'] = '1' grass.run_command('v.to.rast', input=to_rast_input, layer=layer, output='MASK', use='val', val='1', type='area', cats=cats, where=where, env=env) if invert: global tmp tmp = "r_mask_%d" % os.getpid() grass.run_command('g.rename', raster=('MASK', tmp), quiet=True) grass.message(_("Creating inverted raster MASK...")) grass.mapcalc("MASK = if(isnull($tmp), 1, null())", tmp=tmp) grass.verbose(_("Inverted raster MASK created")) else: grass.verbose(_("Raster MASK created")) grass.message(_("All subsequent raster operations will be limited to " "the MASK area. Removing or renaming raster map named " "'MASK' will restore raster operations to normal."))
def main(): infile = options['input'] lesser = options['lesser'] greater = options['greater'] outfile = options['output'] s = grass.read_command("g.region", flags = 'p') kv = grass.parse_key_val(s, sep = ':') s = kv['projection'].strip().split() if s == '0': grass.fatal(_("xy-locations are not supported")) grass.fatal(_("Need projected data with grids in meters")) if not lesser and not greater: grass.fatal(_("You have to specify either lesser= or greater=")) if lesser and greater: grass.fatal(_("lesser= and greater= are mutually exclusive")) if lesser: limit = float(lesser) if greater: limit = float(greater) if not grass.find_file(infile)['name']: grass.fatal(_("Raster map <%s> not found") % infile) clumpfile = "%s.clump.%s" % (infile.split('@')[0], outfile) if not grass.overwrite(): if grass.find_file(clumpfile)['name']: grass.fatal(_("Temporary raster map <%s> exists") % clumpfile) grass.message(_("Generating a clumped raster file ...")) grass.run_command('r.clump', input = infile, output = clumpfile) if lesser: grass.message(_("Generating a reclass map with area size less than or equal to %f hectares...") % limit) else: grass.message(_("Generating a reclass map with area size greater than or equal to %f hectares...") % limit) recfile = outfile + '.recl' p1 = grass.pipe_command('r.stats', flags = 'aln', input = (clumpfile, infile), fs = '|') p2 = grass.feed_command('r.reclass', input = clumpfile, output = recfile, rules = '-') for line in p1.stdout: f = line.rstrip('\r\n').split('|') if len(f) < 5: continue hectares = float(f[4]) * 0.0001 if lesser: test = hectares <= limit else: test = hectares >= limit if test: p2.stdin.write("%s = %s %s\n" % (f[0], f[2], f[3])) p1.wait() p2.stdin.close() p2.wait() grass.message(_("Generating output raster map <%s>...") % outfile) grass.mapcalc("$outfile = $recfile", outfile = outfile, recfile = recfile) grass.run_command('g.remove', rast = [recfile, clumpfile], quiet = True)
def main(): options, flags = grass.parser() xAmap = options['xaraster'] xBmap = options['xbraster'] yAmap = options['yaraster'] yBmap = options['ybraster'] output_basename = options['output'] custom_threshold = options['custom_threshold'] stat_threshold = options['stat_threshold'] Xdelta_name = 'deltaX' Ydelta_name = 'deltaY' anglemap_name = output_basename + '_angle' anglemap_class = anglemap_name + '_class' magnitudemap_name = output_basename + '_magnitude' changemap_name = output_basename + '_change' # Checking that the input maps exist if not grass.find_file(name=xAmap, element='cell')['file']: grass.fatal("xaraster map <%s> not found" % xAmap) if not grass.find_file(name=xBmap, element='cell')['file']: grass.fatal("xbraster map <%s> not found" % xBmap) if not grass.find_file(name=yAmap, element='cell')['file']: grass.fatal("yaraster map <%s> not found" % yAmap) if not grass.find_file(name=xBmap, element='cell')['file']: grass.fatal("ybraster map <%s> not found" % yBmap) TMPRAST.append(Xdelta_name) TMPRAST.append(Ydelta_name) # Calculating delta for X and Y bands grass.message(_("Calculating DeltaX and DeltaY")) delta_calculation(Xdelta_name, xBmap, xAmap) delta_calculation(Ydelta_name, yBmap, yAmap) #Calculating angle and magnitude maps grass.message(_("Writing angle map %s") % anglemap_name) angle_calculation(anglemap_name, Xdelta_name, Ydelta_name) grass.message(_("Writing magnitude map %s") % magnitudemap_name) magnitude_calculation(magnitudemap_name, Xdelta_name, Ydelta_name) # Reclassifing angle map to get a map with the four quadrants keys = ['1', '2', '3', '4'] vals = [0, 90, 180, 270, 360] rvals = [(int(vals[i - 1]), int(vals[i]), keys[i - 1], vals[i - 1], vals[i]) for i in range(1, len(vals))] rules = '\n'.join(['%3d thru %3d = %s %s-%s' % v for v in rvals]) script.write_command('r.reclass', input=anglemap_name, output=anglemap_class, rules='-', overwrite=True, stdin=rules.encode()) # Generating the change detection map using the given threshold if custom_threshold: threshold = custom_threshold grass.message(_("Threshold is %s") % threshold) grass.message(_("Writing change detection map %s") % changemap_name) # Creating the final map of the change, using a custom threshold change_map_calculation(changemap_name, magnitudemap_name, threshold, anglemap_class) elif stat_threshold: #Getting values of mean and standard dev of magnitude to calculate the change detection criteria (> mean + N*stdev) univar = grass.read_command('r.univar', map=magnitudemap_name, flags='g') found = 0 for line in univar.splitlines(): name, val = line.split('=') if name == 'mean': grass.message(_("Mean of magnitude values is: %s") % val) mean = val found += 1 if name == 'stddev': grass.message( _("Standard deviation of magnitude values is: %s") % val) stddev = val found += 1 if found != 2: grass.fatal("Couldn\'t find mean or stddev!") adding_value = float(stat_threshold) * float(stddev) threshold = float(mean) + float(adding_value) grass.message(_("Threshold is %s") % threshold) #Creating the final map of the change, using a statistical threshold change_map_calculation(changemap_name, magnitudemap_name, threshold, anglemap_class) else: grass.message( _("No threshold given, only angle and magnitude maps have been created" )) # anglemap_class: set colors iva_colors = '1 217 255 0\n2 10 214 10\n3 75 173 255\n4 139 105 20\nnv 255 255 255\ndefault 255 255 255' p = grass.feed_command('r.colors', map=anglemap_class, rules='-') p.stdin.write(iva_colors.encode()) p.stdin.close() # anglemap_class: set categories rules = [ '1:moisture reduction', '2:chlorophyll increase', '3:moisture increase', '4:bare soil increase' ] p = grass.feed_command('r.category', map=anglemap_class, rules='-', separator=':') p.stdin.write(('\n'.join(rules)).encode()) p.stdin.close() return 0
def reclass(inf, outf, lim, clump, diag, les): infile = inf outfile = outf lesser = les limit = lim clumped = clump diagonal = diag s = grass.read_command("g.region", flags='p') kv = grass.parse_key_val(s, sep=':') s = kv['projection'].strip().split() if s == '0': grass.fatal(_("xy-locations are not supported")) grass.fatal(_("Need projected data with grids in meters")) if not grass.find_file(infile)['name']: grass.fatal(_("Raster map <%s> not found") % infile) if clumped and diagonal: grass.fatal(_("flags c and d are mutually exclusive")) if clumped: clumpfile = infile else: clumpfile = "%s.clump.%s" % (infile.split('@')[0], outfile) TMPRAST.append(clumpfile) if not grass.overwrite(): if grass.find_file(clumpfile)['name']: grass.fatal(_("Temporary raster map <%s> exists") % clumpfile) if diagonal: grass.message(_("Generating a clumped raster file including " "diagonal neighbors...")) grass.run_command('r.clump', flags='d', input=infile, output=clumpfile) else: grass.message(_("Generating a clumped raster file ...")) grass.run_command('r.clump', input=infile, output=clumpfile) if lesser: grass.message(_("Generating a reclass map with area size less than " "or equal to %f hectares...") % limit) else: grass.message(_("Generating a reclass map with area size greater " "than or equal to %f hectares...") % limit) recfile = outfile + '.recl' TMPRAST.append(recfile) sflags = 'aln' if grass.raster_info(infile)['datatype'] in ('FCELL', 'DCELL'): sflags += 'i' p1 = grass.pipe_command('r.stats', flags=sflags, input=(clumpfile, infile), sep=';') p2 = grass.feed_command('r.reclass', input=clumpfile, output=recfile, rules='-') rules = '' for line in p1.stdout: f = line.rstrip(os.linesep).split(';') if len(f) < 5: continue hectares = float(f[4]) * 0.0001 if lesser: test = hectares <= limit else: test = hectares >= limit if test: rules += "%s = %s %s\n" % (f[0], f[2], f[3]) if rules: p2.stdin.write(rules) p1.wait() p2.stdin.close() p2.wait() if p2.returncode != 0: if lesser: grass.fatal(_("No areas of size less than or equal to %f " "hectares found.") % limit) else: grass.fatal(_("No areas of size greater than or equal to %f " "hectares found.") % limit) grass.mapcalc("$outfile = $recfile", outfile=outfile, recfile=recfile)
def reclass(inf, outf, lim, clump, diag, les): infile = inf outfile = outf lesser = les limit = lim clumped = clump diagonal = diag s = grass.read_command("g.region", flags='p') s = decode(s) kv = grass.parse_key_val(s, sep=':') s = kv['projection'].strip().split() if s == '0': grass.fatal(_("xy-locations are not supported")) grass.fatal(_("Need projected data with grids in meters")) if not grass.find_file(infile)['name']: grass.fatal(_("Raster map <%s> not found") % infile) if clumped and diagonal: grass.fatal(_("flags c and d are mutually exclusive")) if clumped: clumpfile = infile else: clumpfile = "%s.clump.%s" % (infile.split('@')[0], outfile) TMPRAST.append(clumpfile) if not grass.overwrite(): if grass.find_file(clumpfile)['name']: grass.fatal(_("Temporary raster map <%s> exists") % clumpfile) if diagonal: grass.message( _("Generating a clumped raster file including " "diagonal neighbors...")) grass.run_command('r.clump', flags='d', input=infile, output=clumpfile) else: grass.message(_("Generating a clumped raster file ...")) grass.run_command('r.clump', input=infile, output=clumpfile) if lesser: grass.message( _("Generating a reclass map with area size less than " "or equal to %f hectares...") % limit) else: grass.message( _("Generating a reclass map with area size greater " "than or equal to %f hectares...") % limit) recfile = outfile + '.recl' TMPRAST.append(recfile) sflags = 'aln' if grass.raster_info(infile)['datatype'] in ('FCELL', 'DCELL'): sflags += 'i' p1 = grass.pipe_command('r.stats', flags=sflags, input=(clumpfile, infile), sep=';') p2 = grass.feed_command('r.reclass', input=clumpfile, output=recfile, rules='-') rules = '' for line in p1.stdout: f = decode(line).rstrip(os.linesep).split(';') if len(f) < 5: continue hectares = float(f[4]) * 0.0001 if lesser: test = hectares <= limit else: test = hectares >= limit if test: rules += "%s = %s %s\n" % (f[0], f[2], f[3]) if rules: p2.stdin.write(encode(rules)) p1.wait() p2.stdin.close() p2.wait() if p2.returncode != 0: if lesser: grass.fatal( _("No areas of size less than or equal to %f " "hectares found.") % limit) else: grass.fatal( _("No areas of size greater than or equal to %f " "hectares found.") % limit) grass.mapcalc("$outfile = $recfile", outfile=outfile, recfile=recfile)
def calculate_lfp(input, output, coords): prefix = "r_lfp_%d_" % os.getpid() # create the outlet vector map outlet = prefix + "outlet" p = grass.feed_command("v.in.ascii", overwrite=True, input="-", output=outlet, separator=",") p.stdin.write(coords) p.stdin.close() p.wait() if p.returncode != 0: grass.fatal(_("Cannot create the outlet vector map")) # convert the outlet vector map to raster try: grass.run_command("v.to.rast", overwrite=True, input=outlet, output=outlet, use="cat", type="point") except CalledModuleError: grass.fatal(_("Cannot convert the outlet vector to raster")) # calculate the downstream flow length flds = prefix + "flds" try: grass.run_command("r.stream.distance", overwrite=True, flags="om", stream_rast=outlet, direction=input, method="downstream", distance=flds) except CalledModuleError: grass.fatal(_("Cannot calculate the downstream flow length")) # calculate the upstream flow length flus = prefix + "flus" try: grass.run_command("r.stream.distance", overwrite=True, flags="o", stream_rast=outlet, direction=input, method="upstream", distance=flus) except CalledModuleError: grass.fatal(_("Cannot calculate the upstream flow length")) # calculate the sum of downstream and upstream flow lengths fldsus = prefix + "fldsus" try: grass.run_command("r.mapcalc", overwrite=True, expression="%s=%s+%s" % (fldsus, flds, flus)) except CalledModuleError: grass.fatal( _("Cannot calculate the sum of downstream and upstream flow lengths" )) # find the longest flow length p = grass.pipe_command("r.info", flags="r", map=fldsus) max = "" for line in p.stdout: line = line.rstrip("\n") if line.startswith("max="): max = line.split("=")[1] break p.wait() if p.returncode != 0 or max == "": grass.fatal(_("Cannot find the longest flow length")) min = float(max) - 0.0005 # extract the longest flow path lfp = prefix + "lfp" try: grass.run_command("r.mapcalc", overwrite=True, expression="%s=if(%s>=%f, 1, null())" % (lfp, fldsus, min)) except CalledModuleError: grass.fatal(_("Cannot create the longest flow path raster map")) # thin the longest flow path raster map try: grass.run_command("r.thin", input=lfp, output=output) except CalledModuleError: grass.fatal(_("Cannot thin the longest flow path raster map")) # remove intermediate outputs grass.run_command("g.remove", flags="f", type="raster,vector", pattern="%s*" % prefix) # write metadata tmphist = grass.tempfile() f = open(tmphist, "w+") f.write(os.environ["CMDLINE"]) f.close() grass.run_command("r.support", map=output, title="Longest flow path", loadhistory=tmphist, description="generated by r.lfp") grass.try_remove(tmphist)
def main(): raster = options["raster"] maskcats = options["maskcats"] vector = options["vector"] layer = options["layer"] cats = options["cats"] where = options["where"] remove = flags["r"] invert = flags["i"] if not remove and not raster and not vector: grass.fatal(_("Either parameter <raster> ot parameter <vector> is required")) mapset = grass.gisenv()["MAPSET"] exists = bool(grass.find_file("MASK", element="cell", mapset=mapset)["file"]) if remove: # -> remove if exists: grass.run_command("g.remove", flags="f", quiet=True, type="rast", pattern="MASK") grass.message(_("Raster MASK removed")) else: grass.fatal(_("No existing MASK to remove")) else: # -> create if exists: if not grass.overwrite(): grass.fatal(_("MASK already found in current mapset. Delete first or overwrite.")) else: grass.warning(_("MASK already exists and will be overwritten")) grass.run_command("g.remove", flags="f", quiet=True, type="rast", pattern="MASK") if raster: # check if input raster exists if not grass.find_file(raster)["file"]: grass.fatal(_("Raster map <%s> not found") % raster) if maskcats != "*" and not remove: if grass.raster_info(raster)["datatype"] != "CELL": grass.fatal( _( "The raster map <%s> must be integer (CELL type) " " in order to use the 'maskcats' parameter" ) % raster ) p = grass.feed_command("r.reclass", input=raster, output="MASK", overwrite=True, rules="-") p.stdin.write("%s = 1" % maskcats) p.stdin.close() p.wait() elif vector: vector_name = grass.find_file(vector, "vector")["fullname"] if not vector_name: grass.fatal(_("Vector map <%s> not found") % vector) # parser bug? if len(cats) == 0: cats = None if len(where) == 0: where = None if grass.vector_info_topo(vector_name)["areas"] < 1: grass.warning(_("No area found in vector map <%s>. " "Creating a convex hull for MASK.") % vector_name) global tmp_hull tmp_hull = "tmp_hull_%d" % os.getpid() to_rast_input = tmp_hull # force 'flat' convex hull for 3D vector maps if 0 != grass.run_command( "v.hull", flags="f", quiet=True, input=vector_name, output=tmp_hull, layer=layer, cats=cats, where=where, ): grass.fatal(_("Unable to create a convex hull for vector map <%s>") % vector_name) else: to_rast_input = vector_name env = os.environ.copy() if grass.verbosity() > 1: env["GRASS_VERBOSE"] = "1" grass.run_command( "v.to.rast", input=to_rast_input, layer=layer, output="MASK", use="val", val="1", type="area", cats=cats, where=where, env=env, ) if invert: global tmp tmp = "r_mask_%d" % os.getpid() grass.run_command("g.rename", rast=("MASK", tmp), quiet=True) grass.message(_("Creating inverted raster MASK...")) grass.mapcalc("MASK = if(isnull($tmp), 1, null())", tmp=tmp) grass.verbose(_("Inverted raster MASK created")) else: grass.verbose(_("Raster MASK created")) grass.message( _( "All subsequent raster operations will be limited to " "the MASK area. Removing or renaming raster map named " "'MASK' will restore raster operations to normal." ) )
def landscapeEvol(m, o, p, q, res, s, f): """ Now define "landscapeEvol", our main block of code, here defined because of the way g.parser needs to be called with python codes for grass (see below) m = last iteration number, o = iteration number, p = prefx, q = statsout, res = resolution of input elev map, s = master list of lists of climate data f = name of text file to write stats to """ # Get the process id to tag any temporary maps we make for easy clean up in the loop pid = os.getpid() # Get variables from user input elev = options["elev"] transp_eq = options["transp_eq"] initbdrk = options["initbdrk"] outdem = options["outdem"] outsoil = options["outsoil"] sdensity = options["sdensity"] K = options["k"] P = options["p"] C = options["c"] exp_m = options["exp_m"].split(",") exp_n = options["exp_n"].split(",") flowcontrib = options["flowcontrib"] convergence = options["convergence"] manningn = options["manningn"] p = options["prefx"] # Make some variables for temporary map names aspect = "%saspect%04d" % (p, o) flowacc = "%sflowacc%04d" % (p, o) flowdir = "%sflowdir%04d" % (p, o) flacclargenum = "%sflowacclargenum%04d" % (p, o) pc = "%spc%04d" % (p, o) tc = "%stc%04d" % (p, o) qsx = "%sQsx_%04d" % (p, o) qsy = "%sQsy_%04d" % (p, o) qsxdx = "%sDelta_Qsx_%04d" % (p, o) qsydy = "%sDelta_Qsy_%04d" % (p, o) rainexcess = "%s_rainfall_excess_map_%04d" % (p, o) tmpnetchange = "tmp%s_netchange%04d" % (pid, o) tmp90qle = "tmp%s_netchange_90qle%04d" % (pid, o) tmp10qle = "tmp%s_netchange_10qle%04d" % (pid, o) tmperosion = "tmp%s_erosion%04d" % (pid, o) tmpdep = "tmp%s_deposition%04d" % (pid, o) # List of temp maps to remove unless user wants to keep them all mapstoremove = [ aspect, flowacc, flowdir, flacclargenum, pc, tc, rainexcess, tmpnetchange, tmp10qle, tmp90qle, tmperosion, tmpdep, ] # Variables that come in as a list of lists and can update with each iteration # masterlist = [R2,rain2,stormlength2,storms2,stormi2] R = s[0][m] rain = s[1][m] stormtimet = float(s[2][m]) * 3600.00 # Convert storm length to seconds storms = s[3][m] stormi = (float(s[4][m]) * stormtimet ) # Calculate the length of time at peak flow depth # Maps that will update at each iteration to record state of landscape old_dem = "%s%s%04d" % (p, outdem, m) old_soil = "%s%s%04d" % (p, outsoil, m) slope = "%sslope%04d" % (p, o) netchange = "%sED_rate%04d" % (p, o) new_dem = "%s%s%04d" % (p, outdem, o) new_soil = "%s%s%04d" % (p, outsoil, o) # If first iteration, use input maps. Otherwise, use maps generated from # previous iterations if o == 1: grass.run_command("g.copy", raster=elev + "," + old_dem, quiet=True) # Grab the number of cells in the starting DEM numcells = grass.parse_command( "r.univar", flags="g", map=old_dem, )["n"] # Calculate soil as difference between surface and bedrock grass.mapcalc( "${old_soil}=${old_dem}-${initbdrk}", overwrite=True, quiet=True, old_soil=old_soil, old_dem=old_dem, initbdrk=initbdrk, ) grass.message("\n*************************\n" + "Iteration %s -- " % o + "step 1/6: calculating slope\n" + "*************************\n") grass.run_command("r.slope.aspect", quiet=True, elevation=old_dem, aspect=aspect, slope=slope) grass.message("\n*************************\n" + "Iteration %s -- " % o + "step 2/6: calculating accumulated flow depths\n" + "*************************\n") # Make map of rainfall excess (proportion each cell contributes to # downstrem flow) from flowcontrib. Note that if flowcontrib is a map, we # are just making a copy of it. This map is a percentage, but has to be # scaled from 0-100, because r.watershed will only allow values greater # than 1 as input in it's 'flow' variable. This creates a flow accumulation # map with large numbers, which will be divided by 100 after it is # made, bringing the values back down to what they should be. grass.mapcalc( "${rainexcess}=int(${flowcontrib})", quiet=True, rainexcess=rainexcess, flowcontrib=flowcontrib, ) grass.run_command( "r.watershed", quiet=True, flags="a", elevation=old_dem, threshold=numcells, flow=rainexcess, accumulation=flacclargenum, drainage=flowdir, convergence=convergence, ) grass.mapcalc( "${flowacc}=${flacclargenum}/100", quiet=True, flowacc=flowacc, flacclargenum=flacclargenum, ) # again, do something different if we are only making an evaluation of cutoffs if flags["p"] is True: samplePoints(old_dem, aspect, slope, pc, tc, flowacc, p) grass.message("\n*************************\n" + "Iteration %s -- " % o + "step 3/6: calculating sediment transport rates \n" + "*************************\n") # Figure out which transport equation to run. All equations estimate transport capacity as kg/m.s. Note that we integrate the step to calculate the Tc in the east and west directions, to simplify the divergence calculations in the next step (i.e., to reduce the overall number of mapcalc statements and intermediate maps) if transp_eq == "StreamPower": # Stream power equation: Tc=Kt*gw*1/N*h^m*B^n # where: h = depth of flow = (i*A)/(0.595*t) # and: B = change in slope # GIS Implementation: # Tc=K*C*P*gw*(1/N)*((i*A)/(0.595*t))^m*(tan(S)^n) # Variables: # Tc=Transport Capacity [kg/meters.second] # K*C*P=Kt=mitigating effects of soil type, vegetation cover, and landuse practices. [unitless] # gw=Hydrostatic pressure of water 9810 [kg/m2.second] # N=Manning's coefficient ~0.3-0.6 for different types of stream channesl [unitless] # i=rainfall intentsity [m/rainfall event] # A=uplsope accumulated area per contour (cell) width [m2/m] = [m] # 0.595 = constant for time-lagged peak flow (assumes symmetrical unit hydrograph) # t=length of rainfall event [seconds] # S=topographic slope [degrees] # m = transport coefficient for upslope area [unitless] # n transport coefficient for slope [unitless] # SLOPE VERSISON e1 = """${qsx}=${K}*${C}*${P} * exp(${manningn}, -1) * 9810. * \ exp((((${rain}/1000.)*${flowacc})/(0.595*${stormtimet})), \ graph(${flowacc}, ${exp_m1a},${exp_m1b}, ${exp_m2a},${exp_m2b}) ) * \ exp(tan(${slope}), graph(${slope}, ${exp_n1a},${exp_n1b}, ${exp_n2a},${exp_n2b}))\ * cos(${aspect})""" e2 = """${qsy}=${K}*${C}*${P} * exp(${manningn}, -1) * 9810. * \ exp((((${rain}/1000.)*${flowacc})/(0.595*${stormtimet})), \ graph(${flowacc}, ${exp_m1a},${exp_m1b}, ${exp_m2a},${exp_m2b})) * \ exp(tan(${slope}), graph(${slope}, ${exp_n1a},${exp_n1b}, ${exp_n2a},${exp_n2b}))\ * sin(${aspect})""" elif transp_eq == "ShearStress": # Shear stress equation: Tc=Kt*tau^m (critical shear stress assumed to be 0) # where: tau = shear stress = gw*h*B # and: S = change in slope # and: h = depth of flow = (i*A)/(0.595*t) # GIS Implmentation: # Tc=K*C*P*(gw*((i*A)/(0.595*t)*(tan(S))))^m # Variables: # Tc=Transport Capacity [kg/meters.second] # K*C*P=Kt=mitigating effects of soil type, vegetation cover, and landuse practices. [unitless] # gw=Hydrostatic pressure of water 9810 [kg/m2.second] # N=Manning's coefficient ~0.3-0.6 for different types of stream channesl [unitless] # i=rainfall intentsity [m/rainfall event] # A=uplsope accumulated area per contour (cell) width [m2/m] = [m] # 0.595 = constant for time-lagged peak flow (assumes symmetrical unit hydrograph) # t=length of rainfall event [seconds] # B=topographic slope [degrees] # m = transport coefficient (here assumed to be scaled to upslope area) [unitless] e1 = """${qsx}=(${K}*${C}*${P} * \ exp(9810.*(((${rain}/1000)*${flowacc})/(0.595*${stormtimet}))*tan(${slope}), \ graph(${flowacc}, ${exp_n1a},${exp_n1b}, ${exp_n2a},${exp_n2b}))) * \ cos(${aspect})""" e2 = """${qsy}=(${K}*${C}*${P} * \ exp(9810.*(((${rain}/1000)*${flowacc})/(0.595*${stormtimet}))*tan(${slope}), \ graph(${flowacc}, ${exp_n1a},${exp_n1b}, ${exp_n2a},${exp_n2b}) )) * \ sin(${aspect})""" elif transp_eq == "USPED": # USPED equation: Tc=R*K*C*P*A^m*B^n # where: B = change in slope # GIS Implementation: # Tc=R*K*C*P*A^m*tan(S)^n # Variables: # Tc=Transport Capacity [kg/meters.second] # R=Rainfall intensivity factor [MJ.mm/ha.h.yr] # A=uplsope accumulated area per contour (cell) width [m2/m] = [m] # S=topographic slope [degrees] # m = transport coefficient for upslope area [unitless] # n transport coefficient for slope [unitless] e1 = """${qsx}=((${R}*${K}*${C}*${P}*\ exp((${flowacc}*${res}),graph(${flowacc}, ${exp_m1a},${exp_m1b}, ${exp_m2a},${exp_m2b}))*\ exp(sin(${slope}), graph(${slope}, ${exp_n1a},${exp_n1b}, ${exp_n2a},${exp_n2b})))\ * cos(${aspect}))""" e2 = """${qsy}=((${R}*${K}*${C}*${P}*\ exp((${flowacc}*${res}),graph(${flowacc}, ${exp_m1a},${exp_m1b}, ${exp_m2a},${exp_m2b}))*\ exp(sin(${slope}), graph(${slope}, ${exp_n1a},${exp_n1b}, ${exp_n2a},${exp_n2b})))\ * sin(${aspect}))""" else: grass.fatal( 'You have entered a non-viable tranport equation name. Please ensure option "transp_eq" is one of "StreamPower," "ShearStress," or "USPED."' ) # Actually do the mapcalc statement for chosen transport equation x = grass.mapcalc_start( e1, quiet=True, qsx=qsx, slope=slope, aspect=aspect, R=R, K=K, C=C, P=P, res=res, flowacc=flowacc, rain=rain, stormtimet=stormtimet, stormi=stormi, exp_m1a=exp_m[0], exp_m1b=exp_m[1], exp_m2a=exp_m[2], exp_m2b=exp_m[3], exp_n1a=exp_n[0], exp_n1b=exp_n[1], exp_n2a=exp_n[2], exp_n2b=exp_n[3], manningn=manningn, ) y = grass.mapcalc_start( e2, quiet=True, qsy=qsy, slope=slope, aspect=aspect, R=R, K=K, C=C, P=P, res=res, flowacc=flowacc, rain=rain, stormtimet=stormtimet, stormi=stormi, exp_m1a=exp_m[0], exp_m1b=exp_m[1], exp_m2a=exp_m[2], exp_m2b=exp_m[3], exp_n1a=exp_n[0], exp_n1b=exp_n[1], exp_n2a=exp_n[2], exp_n2b=exp_n[3], manningn=manningn, ) x.wait() y.wait() grass.message( "\n*************************\n" + "Iteration %s -- " % o + "step 4/6: calculating divergence/difference of sediment transport and the actual amount of erosion or deposition in vertical meters/cell/year\n" + "*************************\n") # Taking divergence of transport capacity Tc converts kg/m.s to kg/m2.s sax = grass.start_command("r.slope.aspect", quiet=True, elevation=qsx, dx=qsxdx) say = grass.start_command("r.slope.aspect", quiet=True, elevation=qsy, dy=qsydy) sax.wait() say.wait() # Now convert output of divergence to calculated erosion and deposition in # vertical meters of elevation change. Add back the divergence in EW and NS # directions. Units are in kg/m2.s, so start by dividing by soil density # [kg/m3] to get m/s elevation change (for USPED that is m/year already, # but not for the shear stress or stream power). # For shear stress and stream power, also multiply by the number # of seconds at peak flow depth (stormi) and then by the number of erosive # storms per year to get m/year elevation change. if transp_eq == "USPED": ed = """${netchange}=((${qsxdx}+${qsydy})/${sdensity})""" grass.mapcalc( ed, quiet=True, netchange=tmpnetchange, qsxdx=qsxdx, qsydy=qsydy, sdensity=sdensity, ) else: ed = """${netchange}=((${qsxdx}+${qsydy})/${sdensity})*${stormi}*${storms}""" grass.mapcalc( ed, quiet=True, netchange=tmpnetchange, qsxdx=qsxdx, qsydy=qsydy, sdensity=sdensity, stormi=stormi, storms=storms, ) # Apply smoothing to the output to remove some spikes. Map will only be smoothed for values above the 90th quantile and below the 10th quantile (i.e., only extreme values will be smoothed) if flags["m"] is True: a = grass.start_command( "r.neighbors", quiet=True, input=tmpnetchange, output=tmp10qle, method="quantile", size=5, quantile=0.1, ) b = grass.start_command( "r.neighbors", quiet=True, input=tmpnetchange, output=tmp90qle, method="quantile", size=5, quantile=0.9, ) a.wait() b.wait() smoother = """${netchange}=if(${tmpnetchange}<${tmp10qle}, ${tmp10qle}, if(${tmpnetchange}>${tmp90qle}, ${tmp90qle}, ${tmpnetchange}))""" grass.mapcalc( smoother, quiet=True, netchange=netchange, tmpnetchange=tmpnetchange, tmp90qle=tmp90qle, tmp10qle=tmp10qle, ) else: grass.run_command("g.rename", quiet=True, raster=tmpnetchange + "," + netchange) grass.message( "\n*************************\n" + "Iteration %s -- " % o + "step 5/6: calculating terrain evolution and new soil depths\n" + " *************************\n") # Compute elevation changes: addition of ED change to old DEM. # This mapcalc statement first checks the amount of erodable soil in a given # cell against the amount of erosion calculated, and keeps the cell from # eroding past this amount (if there is soil, then if the amount of erosion # is more than the amount of soil, just remove all the soil and stop, else # remove the amount of caclulated erosion. It also runs an error catch that # checks to make sure that soil depth is not negative (could happen, I # suppose), and if it is, corrects it). Finally, do patch-job to catch the # shrinking edge problem (the edge cells have no upstream cell, so get # turned null in the calculations in step 4) e = """${new_dem} = eval(x=if(${old_soil} > 0.0 && (-1*${netchange}) <= ${old_soil}, ${netchange}, \ if((-1*${netchange}) > ${old_soil}, (-1*${old_soil}), 0)), \ y=(${old_dem} + x), if(isnull(y), ${old_dem}, y))""" grass.mapcalc( e, quiet=True, new_dem=new_dem, old_soil=old_soil, old_dem=old_dem, netchange=netchange, ) # Calculate new soil depths by subtracting initial bedrock elevations from # the new DEM. e = """${new_soil} = if((${new_dem} - ${initbdrk}) < 0, 0, (${new_dem} - ${initbdrk}))""" grass.mapcalc(e, quiet=True, new_soil=new_soil, new_dem=new_dem, initbdrk=initbdrk) # Set colors for elevation, soil, and ED maps grass.run_command("r.colors", quiet=True, map=new_dem, color="srtm") sdcolors = [ "100% 0:249:47", "20% 78:151:211", "6% 194:84:171", "0% 227:174:217" ] sdc = grass.feed_command("r.colors", quiet=True, map=new_soil, rules="-") sdc.stdin.write("\n".join(sdcolors)) sdc.stdin.close() nccolors = [ "100 127:0:255", "1 0:0:255", ".1 0:255:0", "0.001 152:251:152", "0 250:250:250", "-0.001 255:255:50", "-.1 255:127:0", "-1 255:0:0", "-100 127:0:255", ] ncc = grass.feed_command("r.colors", quiet=True, map=netchange, rules="-") ncc.stdin.write("\n".join(nccolors)) ncc.stdin.close() sdc.wait() ncc.wait() grass.message("\n*************************\n" + "Iteration %s -- " % o + "step 6/6: writing stats to output file\n" + "*************************\n") # Make some temp maps of just erosion rate and just deposition rates e = """${tmperosion}=if(${netchange} < -0, ${netchange}, null())""" ero1 = grass.mapcalc_start(e, quiet=True, tmperosion=tmperosion, netchange=netchange) e = """${tmpdep}=if(${netchange} > 0, ${netchange}, null())""" dep1 = grass.mapcalc_start(e, quiet=True, tmpdep=tmpdep, netchange=netchange) ero1.wait() dep1.wait() # Grab the stats from these temp files and save them to dictionaries erosstats = grass.parse_command("r.univar", flags="ge", percentile="1", map=tmperosion) depostats = grass.parse_command("r.univar", flags="ge", percentile="99", map=tmpdep) # Finish gathering stats (just need the soil depth stats now) soilstats = grass.parse_command("r.univar", flags="ge", map=new_soil, percentile="99") # Write stats to a new line in the stats file # HEADER of the file should be: ',,Mean Values,,,,Standard Deviations,,,,Totals,,,Additional Stats\nIteration,,Mean Erosion,Mean Deposition,Mean Soil Depth,,Standard Deviation Erosion,Standard Deviation Deposition,Standard Deviation Soil Depth,,Total Sediment Eroded,Total Sediment Deposited,,Minimum Erosion,First Quartile Erosion,Median Erosion,Third Quartile Erosion,Maximum Erosion,Original Un-smoothed Maximum Erosion,,Minimum Deposition,First Quartile Deposition,Median Deposition,Third Quartile Deposition,Maximum Deposition,Original Un-smoothed Maximum Deposition,,Minimum Soil Depth,First Quartile Soil Depth,Median Soil Depth,Third Quartile Soil Depth,Maximum Soil Depth' f.write("\n%s" % o + ",," + erosstats["mean"] + "," + depostats["mean"] + "," + soilstats["mean"] + ",," + erosstats["stddev"] + "," + depostats["stddev"] + "," + soilstats["stddev"] + ",," + erosstats["sum"] + "," + depostats["sum"] + ",," + erosstats["max"] + "," + erosstats["third_quartile"] + "," + erosstats["median"] + "," + erosstats["first_quartile"] + "," + erosstats["min"] + "," + depostats["min"] + "," + depostats["first_quartile"] + "," + depostats["median"] + "," + depostats["third_quartile"] + "," + depostats["max"] + "," + soilstats["min"] + "," + soilstats["first_quartile"] + "," + soilstats["median"] + "," + soilstats["third_quartile"] + "," + soilstats["max"]) # Cleanup temporary files if flags["k"] is True: grass.message("\nTemporary maps will NOT be deleted!!!!\n") else: grass.message("\nCleaning up temporary maps...\n\n") # Check all the flag options, and add to list of maps to delete if flags["s"] is True: grass.message("Keeping Slope map.") else: mapstoremove.append(slope) if flags["d"] is True: grass.message("Not keeping Soil Depth map.") mapstoremove.append(old_soil) # Check if this is the last year and remove the "new-soil" map too if o == int(options["number"]): mapstoremove.append(new_soil) else: # Check if this is the first year, and if so, remove the temporary initial soil depths map if o <= 1: grass.message(("%s%s%04d" % (p, outsoil, m))) mapstoremove.append("%s%s%04d" % (p, outsoil, m)) if flags["e"] is True: grass.message( "Keeping delta Transport Capacity (divergence) maps.") else: mapstoremove.extend([qsxdx, qsydy]) if flags["t"] is True: grass.message("Keeping Transport Capacity maps.") else: mapstoremove.extend([qsx, qsy]) if flags["r"] is True: grass.message("Not keeping an Erosion and Deposition rate map.") mapstoremove.append(netchange) if len(mapstoremove) == 0: pass else: grass.run_command( "g.remove", quiet=True, flags="f", type="rast", name=",".join(mapstoremove), ) grass.message("\n*************************\n" + "Done with Iteration %s " % o + "\n*************************\n") return 0
def main(): color = options['color'] column = options['column'] layer = options['layer'] map = options['map'] range = options['range'] raster = options['raster'] rgb_column = options['rgb_column'] rules = options['rules'] flip = flags['n'] global tmp, tmp_colr, tmp_vcol pid = os.getpid() tmp = tmp_colr = tmp_vcol = None mapset = grass.gisenv()['MAPSET'] gisbase = os.getenv('GISBASE') # does map exist in CURRENT mapset? kv = grass.find_file(map, element = 'vector', mapset = mapset) if not kv['file']: grass.fatal(_("Vector map <%s> not found in current mapset") % map) vector = map.split('@', 1) # sanity check mutually exclusive color options if not options['color'] and not options['raster'] and not options['rules']: grass.fatal(_("Pick one of color, rules, or raster options")) if color: #### check the color rule is valid color_opts = os.listdir(os.path.join(gisbase, 'etc', 'colors')) color_opts += ['random', 'grey.eq', 'grey.log', 'rules'] if color not in color_opts: grass.fatal(_("Invalid color rule <%s>\n") % color + _("Valid options are: %s") % ' '.join(color_opts)) elif raster: if not grass.find_file(raster)['name']: grass.fatal(_("Raster raster map <%s> not found") % raster) elif rules: if not os.access(rules, os.R_OK): grass.fatal(_("Unable to read color rules file <%s>") % rules) # column checks # check input data column cols = grass.vector_columns(map, layer = layer) if column not in cols: grass.fatal(_("Column <%s> not found") % column) ncolumn_type = cols[column]['type'] if ncolumn_type not in ["INTEGER", "DOUBLE PRECISION"]: grass.fatal(_("Column <%s> is not numeric but %s") % (column, ncolumn_type)) # check if GRASSRGB column exists, make it if it doesn't table = grass.vector_db(map)[int(layer)]['table'] if rgb_column not in cols: # RGB Column not found, create it grass.message(_("Creating column <%s>...") % rgb_column) try: grass.run_command('v.db.addcolumn', map = map, layer = layer, column = "%s varchar(11)" % rgb_column) except CalledModuleError: grass.fatal(_("Creating color column")) else: column_type = cols[rgb_column]['type'] if column_type not in ["CHARACTER", "TEXT"]: grass.fatal(_("Column <%s> is not of compatible type (found %s)") % (rgb_column, column_type)) else: num_chars = dict([(v[0], int(v[2])) for v in grass.db_describe(table)['cols']])[rgb_column] if num_chars < 11: grass.fatal(_("Color column <%s> is not wide enough (needs 11 characters)"), rgb_column) cvals = grass.vector_db_select(map, layer = int(layer), columns = column)['values'].values() # find data range if range: # order doesn't matter vals = range.split(',') else: grass.message(_("Scanning values...")) vals = [float(x[0]) for x in cvals] minval = min(vals) maxval = max(vals) grass.verbose(_("Range: [%s, %s]") % (minval, maxval)) if minval is None or maxval is None: grass.fatal(_("Scanning data range")) # setup internal region grass.use_temp_region() grass.run_command('g.region', rows = 2, cols = 2) tmp_colr = "tmp_colr_%d" % pid # create dummy raster map if ncolumn_type == "INTEGER": grass.mapcalc("$tmp_colr = int(if(row() == 1, $minval, $maxval))", tmp_colr = tmp_colr, minval = minval, maxval = maxval) else: grass.mapcalc("$tmp_colr = double(if(row() == 1, $minval, $maxval))", tmp_colr = tmp_colr, minval = minval, maxval = maxval) if color: color_cmd = {'color': color} elif raster: color_cmd = {'raster': raster} elif rules: color_cmd = {'rules': rules} if flip: flip_flag = 'n' else: flip_flag = '' grass.run_command('r.colors', map = tmp_colr, flags = flip_flag, quiet = True, **color_cmd) tmp = grass.tempfile() # calculate colors and write SQL command file grass.message(_("Looking up colors...")) f = open(tmp, 'w') p = grass.feed_command('r.what.color', flags = 'i', input = tmp_colr, stdout = f) lastval = None for v in sorted(vals): if v == lastval: continue p.stdin.write('%f\n' % v) p.stdin.close() p.wait() f.close() tmp_vcol = "%s_vcol.sql" % tmp fi = open(tmp, 'r') fo = open(tmp_vcol, 'w') t = string.Template("UPDATE $table SET $rgb_column = '$colr' WHERE $column = $value;\n") found = 0 for line in fi: [value, colr] = line.split(': ') colr = colr.strip() if len(colr.split(':')) != 3: continue fo.write(t.substitute(table = table, rgb_column = rgb_column, colr = colr, column = column, value = value)) found += 1 fi.close() fo.close() if not found: grass.fatal(_("No values found in color range")) # apply SQL commands to update the table with values grass.message(_("Writing %s colors...") % found) try: grass.run_command('db.execute', input = tmp_vcol) except CalledModuleError: grass.fatal(_("Processing SQL transaction")) if flags['s']: vcolors = "vcolors_%d" % pid grass.run_command('g.rename', raster = (tmp_colr, vcolors), quiet = True) grass.message(_("Raster map containing color rules saved to <%s>") % vcolors) # TODO save full v.colors command line history grass.run_command('r.support', map = vcolors, history = "", source1 = "vector map = %s" % map, source2 = "column = %s" % column, title = _("Dummy raster to use as thematic vector legend"), description = "generated by v.colors using r.mapcalc") grass.run_command('r.support', map = vcolors, history = _("RGB saved into <%s> using <%s%s%s>") % (rgb_column, color, raster, rules))
def main(): raster = options['raster'] maskcats = options['maskcats'] vector = options['vector'] layer = options['layer'] cats = options['cats'] where = options['where'] remove = flags['r'] invert = flags['i'] if not remove and not raster and not vector: grass.fatal( _("Either parameter <raster> ot parameter <vector> is required")) mapset = grass.gisenv()['MAPSET'] exists = bool( grass.find_file('MASK', element='cell', mapset=mapset)['file']) if remove: # -> remove if exists: grass.run_command('g.remove', flags='f', quiet=True, type='raster', name='MASK') grass.message(_("Raster MASK removed")) else: grass.fatal(_("No existing MASK to remove")) else: # -> create if exists: if not grass.overwrite(): grass.fatal( _("MASK already found in current mapset. Delete first or overwrite." )) else: grass.warning(_("MASK already exists and will be overwritten")) grass.run_command('g.remove', flags='f', quiet=True, type='raster', name='MASK') if raster: # check if input raster exists if not grass.find_file(raster)['file']: grass.fatal(_("Raster map <%s> not found") % raster) if maskcats != '*' and not remove: if grass.raster_info(raster)['datatype'] != "CELL": grass.fatal( _("The raster map <%s> must be integer (CELL type) " " in order to use the 'maskcats' parameter") % raster) p = grass.feed_command('r.reclass', input=raster, output='MASK', overwrite=True, rules='-') p.stdin.write("%s = 1" % maskcats) p.stdin.close() p.wait() elif vector: vector_name = grass.find_file(vector, 'vector')['fullname'] if not vector_name: grass.fatal(_("Vector map <%s> not found") % vector) # parser bug? if len(cats) == 0: cats = None if len(where) == 0: where = None if grass.vector_info_topo(vector_name)['areas'] < 1: grass.warning( _("No area found in vector map <%s>. " "Creating a convex hull for MASK.") % vector_name) global tmp_hull tmp_hull = "tmp_hull_%d" % os.getpid() to_rast_input = tmp_hull # force 'flat' convex hull for 3D vector maps try: grass.run_command('v.hull', flags='f', quiet=True, input=vector_name, output=tmp_hull, layer=layer, cats=cats, where=where) except CalledModuleError: grass.fatal( _("Unable to create a convex hull for vector map <%s>") % vector_name) else: to_rast_input = vector_name env = os.environ.copy() if grass.verbosity() > 1: env['GRASS_VERBOSE'] = '1' grass.run_command('v.to.rast', input=to_rast_input, layer=layer, output='MASK', use='val', val='1', type='area', cats=cats, where=where, env=env) if invert: global tmp tmp = "r_mask_%d" % os.getpid() grass.run_command('g.rename', raster=('MASK', tmp), quiet=True) grass.message(_("Creating inverted raster MASK...")) grass.mapcalc("MASK = if(isnull($tmp), 1, null())", tmp=tmp) grass.verbose(_("Inverted raster MASK created")) else: grass.verbose(_("Raster MASK created")) grass.message( _("All subsequent raster operations will be limited to " "the MASK area. Removing or renaming raster map named " "'MASK' will restore raster operations to normal."))
def main(): global temp_dist, temp_src input = options['input'] output = options['output'] distances = options['distances'] units = options['units'] zero = flags['z'] tmp = str(os.getpid()) temp_dist = "r.buffer.tmp.%s.dist" % tmp temp_src = "r.buffer.tmp.%s.src" % tmp #check if input file exists if not grass.find_file(input)['file']: grass.fatal(_("<%s> does not exist.") % input) scale = scales[units] distances = distances.split(',') distances1 = [scale * float(d) for d in distances] distances2 = [d * d for d in distances1] s = grass.read_command("g.proj", flags='j') kv = grass.parse_key_val(s) if kv['+proj'] == 'longlat': metric = 'geodesic' else: metric = 'squared' grass.run_command('r.grow.distance', input = input, metric = metric, distance = temp_dist) if zero: exp = "$temp_src = if($input == 0,null(),1)" else: exp = "$temp_src = if(isnull($input),null(),1)" grass.message(_("Extracting buffers (1/2)...")) grass.mapcalc(exp, temp_src = temp_src, input = input) exp = "$output = if(!isnull($input),$input,%s)" for n, dist2 in enumerate(distances2): exp %= "if($dist <= %f,%d,%%s)" % (dist2,n + 2) exp %= "null()" grass.message(_("Extracting buffers (2/2)...")) grass.mapcalc(exp, output = output, input = temp_src, dist = temp_dist) p = grass.feed_command('r.category', map = output, rules = '-') p.stdin.write("1:distances calculated from these locations\n") d0 = "0" for n, d in enumerate(distances): p.stdin.write("%d:%s-%s %s\n" % (n + 2, d0, d, units)) d0 = d p.stdin.close() p.wait() grass.run_command('r.colors', map = output, color = 'rainbow') # write cmd history: grass.raster_history(output)
def main(): table = options["table"] column = options["column"] otable = options["other_table"] ocolumn = options["other_column"] if options["subset_columns"]: scolumns = options["subset_columns"].split(",") else: scolumns = None database = options["database"] driver = options["driver"] # this error handling is completely different among th db.* scripts - FIX if not database: database = None if not driver: driver = None if driver == "dbf": grass.fatal(_("JOIN is not supported for tables stored in DBF format")) # describe input table all_cols_tt = grass.db_describe(table, driver=driver, database=database)["cols"] if not all_cols_tt: grass.fatal(_("Unable to describe table <%s>") % table) found = False # check if column is in input table if column not in [col[0] for col in all_cols_tt]: grass.fatal(_("Column <%s> not found in table <%s>") % (column, table)) # describe other table all_cols_ot = grass.db_describe(otable, driver=driver, database=database)["cols"] # check if ocolumn is in other table if ocolumn not in [ocol[0] for ocol in all_cols_ot]: grass.fatal( _("Column <%s> not found in table <%s>") % (ocolumn, otable)) # determine columns subset from other table if not scolumns: # select all columns from other table cols_to_add = all_cols_ot else: cols_to_add = [] # check if scolumns exists in the other table for scol in scolumns: found = False for col_ot in all_cols_ot: if scol == col_ot[0]: found = True cols_to_add.append(col_ot) break if not found: grass.warning( _("Column <%s> not found in table <%s>") % (scol, otable)) select = "SELECT $colname FROM $otable WHERE $otable.$ocolumn=$table.$column" template = string.Template("UPDATE $table SET $colname=(%s);" % select) for col in cols_to_add: # skip the vector column which is used for join colname = col[0] if colname == column: continue use_len = False if len(col) > 2: use_len = True # Sqlite 3 does not support the precision number any more if driver == "sqlite": use_len = False # MySQL - expect format DOUBLE PRECISION(M,D), see #2792 elif driver == "mysql" and col[1] == "DOUBLE PRECISION": use_len = False if use_len: coltype = "%s(%s)" % (col[1], col[2]) else: coltype = "%s" % col[1] colspec = "%s %s" % (colname, coltype) # add only the new column to the table if colname not in all_cols_tt: p = grass.feed_command("db.execute", input="-", database=database, driver=driver) p.stdin.write("ALTER TABLE %s ADD COLUMN %s" % (table, colspec)) grass.debug("ALTER TABLE %s ADD COLUMN %s" % (table, colspec)) p.stdin.close() if p.wait() != 0: grass.fatal(_("Unable to add column <%s>.") % colname) stmt = template.substitute(table=table, column=column, otable=otable, ocolumn=ocolumn, colname=colname) grass.debug(stmt, 1) grass.verbose( _("Updating column <%s> of table <%s>...") % (colname, table)) try: grass.write_command("db.execute", stdin=stmt, input="-", database=database, driver=driver) except CalledModuleError: grass.fatal(_("Error filling column <%s>") % colname) return 0
def import_cloud_masks(self, area_threshold, prob_threshold, output, shadows, reproject): try: if os.environ["GRASS_OVERWRITE"] == "1": overwrite = True except Exception as e: overwrite = False # Import cloud masks for L2A products files_L2A = self._filter("MSK_CLDPRB_20m.jp2") for f in files_L2A: safe_dir = os.path.dirname(f).split(os.path.sep)[-4] items = safe_dir.split("_") # Define names of final & temporary maps map_name = "_".join([items[5], items[2], "MSK", "CLOUDS"]) clouds_imported = "_".join([items[5], items[2], "cloudprob"]) clouds_selected = "_".join([items[5], items[2], "clouds_selected"]) shadows_imported = "_".join([items[5], items[2], "shadows"]) shadows_selected = "_".join( [items[5], items[2], "shadows_selected"]) mask_selected = "_".join([items[5], items[2], "mask_selected"]) mask_cleaned = "_".join([items[5], items[2], "mask_cleaned"]) self._map_list.extend([ clouds_imported, clouds_selected, shadows_imported, shadows_selected, mask_selected, mask_cleaned, ]) # check if mask alrady exist if gs.find_file(name=map_name, element=output)["file"] and not overwrite: gs.message( _("option <output>: <{}> exists. To overwrite, use the --overwrite flag" .format(map_name))) continue try: # Import & Threshold cloud probability layer gs.message( _("Importing cloud mask for {}").format("_".join( [items[5], items[2]]))) if reproject: self._args["resolution_value"] = self._raster_resolution(f) self._args["resample"] = "bilinear" gs.run_command("r.import", input=f, output=clouds_imported, **self._args) else: gs.run_command("r.in.gdal", input=f, output=clouds_imported, **self._args) gs.use_temp_region() gs.run_command("g.region", raster=clouds_imported) gs.mapcalc( f"{clouds_selected} = if({clouds_imported} >= {prob_threshold}, 1, 0)" ) gs.del_temp_region() # Add shadow mask if shadows: try: shadow_file = self._filter("_".join( [items[5], items[2], "SCL_20m.jp2"])) if reproject: self._args[ "resolution_value"] = self._raster_resolution( shadow_file[0]) self._args["resample"] = "nearest" gs.run_command( "r.import", input=shadow_file, output=shadows_imported, **self._args, ) else: gs.run_command( "r.in.gdal", input=shadow_file, output=shadows_imported, **self._args, ) gs.use_temp_region() gs.run_command("g.region", raster=shadows_imported) gs.mapcalc( f"{shadows_selected} = if({shadows_imported} == 3, 2, 0)" ) gs.mapcalc( f"{mask_selected} = max({shadows_selected},{clouds_selected})" ) gs.del_temp_region() except Exception as e: gs.warning( _("Unable to import shadows for {}. Error: {}"). format("_".join([items[5], items[2]]), e)) else: gs.run_command("g.rename", quiet=True, raster=(clouds_selected, mask_selected)) gs.use_temp_region() gs.run_command("g.region", raster=mask_selected) # Cleaning small patches try: gs.run_command( "r.reclass.area", input=mask_selected, output=mask_cleaned, value=area_threshold, mode="greater", ) except Exception as e: pass # error already printed # Extract & Label clouds (and shadows) gs.run_command("r.null", map=mask_cleaned, setnull="0") labels = ["1:clouds", "2:shadows"] labelling = gs.feed_command("r.category", map=mask_cleaned, separator=":", rules="-") labelling.stdin.write("\n".join(labels).encode()) labelling.stdin.close() labelling.wait() info_stats = gs.parse_command("r.stats", input=mask_cleaned, flags="p") # Create final cloud (and shadow) mask & display areal statistics if output == "vector": gs.run_command( "r.to.vect", input=mask_cleaned, output=map_name, type="area", flags="s", ) colours = ["1 230:230:230", "2 60:60:60"] colourise = gs.feed_command( "v.colors", map=map_name, use="attr", column="value", rules="-", quiet=True, ) colourise.stdin.write("\n".join(colours).encode()) colourise.stdin.close() colourise.wait() gs.vector_history(map_name) else: gs.run_command("g.rename", quiet=True, raster=(mask_cleaned, map_name)) colours = ["1 230:230:230", "2 60:60:60"] colourise = gs.feed_command("r.colors", map=map_name, rules="-", quiet=True) colourise.stdin.write("\n".join(colours).encode()) colourise.stdin.close() colourise.wait() gs.raster_history(map_name) gs.message( _("Areal proportion of masked clouds:{}").format( [key.split()[1] for key in info_stats][0])) if shadows: if len(info_stats) > 2: gs.message( _("Areal proportion of masked shadows:{}").format( [key.split()[1] for key in info_stats][1])) else: gs.message(_("Areal proportion of masked shadows:0%")) gs.del_temp_region() except Exception as e: gs.del_temp_region() gs.warning( _("Unable to import cloud mask for {}. Error: {}").format( "_".join([items[5], items[2]]), e)) # Import of simplified cloud masks for Level-1C products all_files = self._filter("MSK_CLOUDS_B00.gml") files_L1C = [] for f in all_files: safe_dir = os.path.dirname(f).split(os.path.sep)[-4] if safe_dir not in [ os.path.dirname(file).split(os.path.sep)[-4] for file in files_L2A ]: files_L1C.append(f) if len(files_L1C) > 0: from osgeo import ogr for f in files_L1C: safe_dir = os.path.dirname(f).split(os.path.sep)[-4] items = safe_dir.split("_") # Define names of final & temporary maps map_name = "_".join([items[5], items[2], "MSK", "CLOUDS"]) clouds_imported = "_".join( [items[5], items[2], "clouds_imported"]) mask_cleaned = "_".join([items[5], items[2], "mask_cleaned"]) self._map_list.extend([clouds_imported, mask_cleaned]) # check if mask alrady exist if (gs.find_file(name=map_name, element=output)["file"] and not overwrite): gs.fatal( _("option <output>: <{}> exists. To overwrite, use the --overwrite flag" .format(map_name))) continue # check if any OGR layer dsn = ogr.Open(f) layer_count = dsn.GetLayerCount() dsn.Destroy() if layer_count < 1: gs.info( "No clouds layer found in <{}>. Import skipped".format( f)) continue # Import cloud layer try: gs.message( _("Importing cloud mask for {}").format("_".join( [items[5], items[2]]))) gs.run_command( "v.import", input=f, output=clouds_imported, extent=options["extent"], flags="o" if flags["o"] else None, quiet=True, ) gs.use_temp_region() gs.run_command("g.region", vector=clouds_imported) # Cleaning small patches gs.run_command( "v.clean", input=clouds_imported, output=mask_cleaned, tool="rmarea", threshold=area_threshold, ) # Calculating info stats gs.run_command("v.db.addcolumn", map=mask_cleaned, columns="value_num INT") gs.run_command("v.db.update", map=mask_cleaned, column="value_num", value=1) gs.run_command( "v.to.rast", input=mask_cleaned, output=mask_cleaned, use="attr", attribute_column="value_num", quiet=True, ) info_stats = gs.parse_command("r.stats", input=mask_cleaned, flags="p") # Create final cloud mask output if output == "vector": gs.run_command("g.rename", quiet=True, vector=(mask_cleaned, map_name)) colours = ["1 230:230:230"] colourise = gs.feed_command( "v.colors", map=map_name, use="attr", column="value_num", rules="-", quiet=True, ) colourise.stdin.write("\n".join(colours).encode()) colourise.stdin.close() colourise.wait() gs.vector_history(map_name) else: gs.run_command("g.rename", quiet=True, raster=(mask_cleaned, map_name)) colours = ["1 230:230:230"] colourise = gs.feed_command("r.colors", map=map_name, rules="-", quiet=True) colourise.stdin.write("\n".join(colours).encode()) colourise.stdin.close() colourise.wait() gs.raster_history(map_name) # Display messages & statistics if shadows: gs.warning( _("Level1 product: No shadow mask for {}").format( "_".join([items[5], items[2]]))) gs.message( _("Areal proportion of masked clouds:{}").format( [key.split()[1] for key in info_stats][0])) gs.del_temp_region() except Exception as e: gs.del_temp_region() gs.warning( _("Unable to import cloud mask for {}. Error: {}"). format("_".join([items[5], items[2]]), e))
def main(): try: import projpicker as ppik except ImportError: grass.fatal( _("ProjPicker not installed. Use 'pip install projpicker'")) coords = options["coordinates"] operator = options["operator"] query = options["query"] infile = options["input"] outfile = options["output"] fmt = options["format"] separator = options["separator"] bbox_map = options["bbox_map"] overwrite = grass.overwrite() latlon = flags["l"] print_geoms = flags["p"] no_header = flags["n"] single = flags["1"] start_gui = flags["g"] if bbox_map and grass.parse_command("g.proj", flags="g")["unit"] != "degree": grass.fatal(_("Cannot create vector in degree in a non-degree mapset")) # ppik.projpicker() appends input file contents to geometries from # arguments, but it can be confusing and is not supported in this module if coords: query = f"{operator}" coords = coords.split(",") for x, y in zip(coords[0::2], coords[1::2]): if latlon: x, y = y, x query += f" {y},{x}" if infile: geoms = ppik.read_file(infile) else: geoms = query.split() n = len(geoms) idx = [] i = 0 while i < n - 1: m = re.match("""^(|unit=)(["'])(.*)$""", geoms[i]) if m: geoms[i] = m[1] + m[3] quote = m[2] if geoms[i].endswith(quote): geoms[i] = geoms[i][:-len(quote)] else: for j in range(i + 1, n): idx.append(j) m = re.match(f"^(.*){quote}$", geoms[j]) if m: geoms[i] += f" {m[1]}" break else: geoms[i] += f" {geoms[j]}" i = j i += 1 for i in reversed(idx): del geoms[i] if separator == "pipe for plain; newline for srid": if fmt == "plain": separator = "|" elif fmt == "srid": separator = "\n" else: separator = grass.utils.separator(separator) bbox = ppik.projpicker( geoms=geoms, outfile=outfile, fmt=fmt, no_header=no_header, separator=separator, print_geoms=print_geoms, overwrite=overwrite, start_gui=start_gui, single=single, ) if bbox_map: p = grass.feed_command( "v.in.ascii", input="-", output=bbox_map, format="standard", flags="n", ) nbbox = len(bbox) for i in range(0, nbbox): b = bbox[i] cat = i + 1 s = b.south_lat n = b.north_lat w = b.west_lon e = b.east_lon x = (w + e) / 2 y = (s + n) / 2 line = f"L 5 1\n{w} {s}\n{w} {n}\n{e} {n}\n{e} {s}\n{w} {s}\n1 {cat}\n" # XXX: these two lines don't work probably because areas overlap? # line = ( # f"B 5 1\n{w} {s}\n{w} {n}\n{e} {n}\n{e} {s}\n{w} {s}\n" # f"1 {cat}\nC 1 1\n{x} {y}\n1 {cat}\n" # ) # line = ( # f"B 5\n{w} {s}\n{w} {n}\n{e} {n}\n{e} {s}\n{w} {s}\n" # f"C 1 1\n{x} {y}\n1 {cat}\n" # ) line = line.encode() p.stdin.write(line) p.stdin.close() p.wait() if p.returncode != 0: grass.fatal(_("Error creating output vector map %s") % bbox_map) grass.run_command("v.db.addtable", map=bbox_map, columns="srid text, name text") for i in range(0, nbbox): message("\b" * 80 + _("Populating table...") + f" {i+1}/{nbbox}", "") b = bbox[i] srid = f"{b.crs_auth_name}:{b.crs_code}" cat = i + 1 grass.run_command( "db.execute", sql=(f"UPDATE {bbox_map} " f"SET srid='{srid}', " f"""name='{b.crs_name.replace("'", "''")}' """ f"WHERE cat={cat}"), ) message()