def worker(cmd): window, src = cmd reg = Region() old_reg = deepcopy(reg) try: # update region reg.north = dict(window)['north'] reg.south = dict(window)['south'] reg.west = dict(window)['west'] reg.east = dict(window)['east'] reg.set_current() reg.write() reg.set_raster_region() # read raster data with RasterRow(src) as rs: arr = np.asarray(rs) except: pass finally: # reset region old_reg.write() reg.set_raster_region() return(arr)
def test_resampling_to_numpy(self): region = Region() region.ewres = 0.1 region.nsres = 0.1 region.adjust() region.set_raster_region() a = raster2numpy(self.name) self.assertEqual(len(a), 400) region.ewres = 1 region.nsres = 1 region.adjust() region.set_raster_region() a = raster2numpy(self.name) self.assertEqual(len(a), 40) region.ewres = 5 region.nsres = 5 region.adjust() region.set_raster_region() a = raster2numpy(self.name) self.assertEqual(len(a), 8)
def main(): """Do the main work""" # set numpy printing options np.set_printoptions(formatter={"float": lambda x: "{0:0.2f}".format(x)}) # ========================================================================== # Input data # ========================================================================== # Required r_output = options["output"] r_dsm = options["input"] dsm_type = grass.parse_command("r.info", map=r_dsm, flags="g")["datatype"] # Test if DSM exist gfile_dsm = grass.find_file(name=r_dsm, element="cell") if not gfile_dsm["file"]: grass.fatal("Raster map <{}> not found".format(r_dsm)) # Exposure settings v_source = options["sampling_points"] r_source = options["source"] source_cat = options["sourcecat"] r_weights = options["weights"] # test if source vector map exist and contains points if v_source: gfile_vsource = grass.find_file(name=v_source, element="vector") if not gfile_vsource["file"]: grass.fatal("Vector map <{}> not found".format(v_source)) if not grass.vector.vector_info_topo(v_source, layer=1)["points"] > 0: grass.fatal("Vector map <{}> does not contain any points.".format( v_source)) if r_source: gfile_rsource = grass.find_file(name=r_source, element="cell") if not gfile_rsource["file"]: grass.fatal("Raster map <{}> not found".format(r_source)) # if source_cat is set, check that r_source is CELL source_datatype = grass.parse_command("r.info", map=r_source, flags="g")["datatype"] if source_cat != "*" and source_datatype != "CELL": grass.fatal( "The raster map <%s> must be integer (CELL type) in order to \ use the 'sourcecat' parameter" % r_source) if r_weights: gfile_weights = grass.find_file(name=r_weights, element="cell") if not gfile_weights["file"]: grass.fatal("Raster map <{}> not found".format(r_weights)) # Viewshed settings range_inp = float(options["range"]) v_elevation = float(options["observer_elevation"]) b_1 = float(options["b1_distance"]) pfunction = options["function"] refr_coeff = float(options["refraction_coeff"]) flagstring = "" if flags["r"]: flagstring += "r" if flags["c"]: flagstring += "c" # test values if v_elevation < 0.0: grass.fatal("Observer elevation must be larger than or equal to 0.0.") if range_inp <= 0.0 and range_inp != -1: grass.fatal("Exposure range must be larger than 0.0.") if pfunction == "Fuzzy_viewshed" and range_inp == -1: grass.fatal("Exposure range cannot be \ infinity for fuzzy viewshed approch.") if pfunction == "Fuzzy_viewshed" and b_1 > range_inp: grass.fatal("Exposure range must be larger than radius around \ the viewpoint where clarity is perfect.") # Sampling settings source_sample_density = float(options["sample_density"]) seed = options["seed"] if not seed: # if seed is not set, set it to process number seed = os.getpid() # Optional cores = int(options["nprocs"]) memory = int(options["memory"]) # ========================================================================== # Region settings # ========================================================================== # check that location is not in lat/long if grass.locn_is_latlong(): grass.fatal("The analysis is not available for lat/long coordinates.") # get comp. region parameters reg = Region() # check that NSRES equals EWRES if abs(reg.ewres - reg.nsres) > 1e-6: grass.fatal("Variable north-south and east-west 2D grid resolution \ is not supported") # adjust exposure range as a multiplicate of region resolution # if infinite, set exposure range to the max of region size if range_inp != -1: multiplicate = math.floor(range_inp / reg.nsres) exp_range = multiplicate * reg.nsres else: range_inf = max(reg.north - reg.south, reg.east - reg.west) multiplicate = math.floor(range_inf / reg.nsres) exp_range = multiplicate * reg.nsres if RasterRow("MASK", Mapset().name).exist(): grass.warning("Current MASK is temporarily renamed.") unset_mask() # ========================================================================== # Random sample exposure source with target points T # ========================================================================== if v_source: # go for using input vector map as sampling points v_source_sample = v_source grass.verbose("Using sampling points from input vector map") else: # go for sampling # min. distance between samples set to half of region resolution # (issue in r.random.cells) sample_distance = reg.nsres / 2 v_source_sample = sample_raster_with_points( r_source, source_cat, source_sample_density, sample_distance, "{}_rand_pts_vect".format(TEMPNAME), seed, ) # ========================================================================== # Get coordinates and attributes of target points T # ========================================================================== # Prepare a list of maps to extract attributes from # DSM values attr_map_list = [r_dsm] if pfunction in ["Solid_angle", "Visual_magnitude"]: grass.verbose("Precomputing parameter maps...") # Precompute values A, B, C, D for solid angle function # using moving window [row, col] if pfunction == "Solid_angle": r_a_z = "{}_A_z".format(TEMPNAME) r_b_z = "{}_B_z".format(TEMPNAME) r_c_z = "{}_C_z".format(TEMPNAME) r_d_z = "{}_D_z".format(TEMPNAME) expr = ";".join([ "$outmap_A = ($inmap[0, 0] + \ $inmap[0, -1] + \ $inmap[1, -1] + \ $inmap[1, 0]) / 4", "$outmap_B = ($inmap[-1, 0] + \ $inmap[-1, -1] + \ $inmap[0, -1] + \ $inmap[0, 0]) / 4", "$outmap_C = ($inmap[-1, 1] + \ $inmap[-1, 0] + \ $inmap[0, 0] + \ $inmap[0, 1]) / 4", "$outmap_D = ($inmap[0, 1] + \ $inmap[0, 0] + \ $inmap[1, 0] + \ $inmap[1, 1]) / 4", ]) grass.mapcalc( expr, inmap=r_dsm, outmap_A=r_a_z, outmap_B=r_b_z, outmap_C=r_c_z, outmap_D=r_d_z, overwrite=True, quiet=grass.verbosity() <= 1, ) attr_map_list.extend([r_a_z, r_b_z, r_c_z, r_d_z]) # Precompute values slopes in e-w direction, n-s direction # as atan(dz/dx) (e-w direction), atan(dz/dy) (n-s direction) # using moving window [row, col] elif pfunction == "Visual_magnitude": r_slope_ew = "{}_slope_ew".format(TEMPNAME) r_slope_ns = "{}_slope_ns".format(TEMPNAME) expr = ";".join([ "$outmap_ew = atan((sqrt(2) * $inmap[-1, 1] + \ 2 * $inmap[0, 1] + \ sqrt(2) * $inmap[1, 1] - \ sqrt(2) * $inmap[-1, -1] - \ 2 * $inmap[0, -1] - \ sqrt(2) * $inmap[1, -1]) / \ (8 * $w_ew))", "$outmap_ns = atan((sqrt(2) * $inmap[-1, -1] + \ 2 * $inmap[-1, 0] + \ sqrt(2) * $inmap[-1, 1] - \ sqrt(2) * $inmap[1, -1] - \ 2 * $inmap[1, 0] - \ sqrt(2) * $inmap[1, 1]) / \ (8 * $w_ns))", ]) grass.mapcalc( expr, inmap=r_dsm, outmap_ew=r_slope_ew, outmap_ns=r_slope_ns, w_ew=reg.ewres, w_ns=reg.nsres, overwrite=True, quiet=grass.verbosity() <= 1, ) attr_map_list.extend([r_slope_ew, r_slope_ns]) # Use viewshed weights if provided if r_weights: attr_map_list.append(r_weights) # Extract attribute values target_pts_grass = grass.read_command( "r.what", flags="v", map=attr_map_list, points=v_source_sample, separator="|", null_value="*", quiet=True, ) # columns to use depending on parametrization function usecols = list(range(0, 4 + len(attr_map_list))) usecols.remove(3) # skip 3rd column - site_name # convert coordinates and attributes of target points T to numpy array target_pts_np = txt2numpy( target_pts_grass, sep="|", names=None, null_value="*", usecols=usecols, structured=False, ) # if one point only - 0D array which cannot be used in iteration if target_pts_np.ndim == 1: target_pts_np = target_pts_np.reshape(1, -1) target_pts_np = target_pts_np[~np.isnan(target_pts_np).any(axis=1)] no_points = target_pts_np.shape[0] # if viewshed weights not set by flag - set weight to 1 for all pts if not r_weights: weights_np = np.ones((no_points, 1)) target_pts_np = np.hstack((target_pts_np, weights_np)) grass.debug("target_pts_np: {}".format(target_pts_np)) # ========================================================================== # Calculate weighted parametrised cummulative viewshed # by iterating over target points T # ========================================================================== grass.verbose("Calculating partial viewsheds...") # Parametrisation function if pfunction == "Solid_angle": parametrise_viewshed = solid_angle_reverse elif pfunction == "Distance_decay": parametrise_viewshed = distance_decay_reverse elif pfunction == "Fuzzy_viewshed": parametrise_viewshed = fuzzy_viewshed_reverse elif pfunction == "Visual_magnitude": parametrise_viewshed = visual_magnitude_reverse else: parametrise_viewshed = binary # Collect variables that will be used in do_it_all() into a dictionary global_vars = { "region": reg, "range": exp_range, "param_viewshed": parametrise_viewshed, "observer_elevation": v_elevation, "b_1": b_1, "memory": memory, "refr_coeff": refr_coeff, "flagstring": flagstring, "r_dsm": r_dsm, "dsm_type": dsm_type, "cores": cores, "tempname": TEMPNAME, } # Split target points to chunks for each core target_pnts = np.array_split(target_pts_np, cores) # Combine each chunk with dictionary combo = list(zip(itertools.repeat(global_vars), target_pnts)) # Calculate partial cummulative viewshed with Pool(cores) as pool: np_sum = pool.starmap(do_it_all, combo) pool.close() pool.join() # We should probably use nansum here? all_nan = np.all(np.isnan(np_sum), axis=0) np_sum = np.nansum(np_sum, axis=0, dtype=np.single) np_sum[all_nan] = np.nan grass.verbose("Writing final result and cleaning up...") # Restore original computational region reg.read() reg.set_current() reg.set_raster_region() # Convert numpy array of cummulative viewshed to raster numpy2raster(np_sum, mtype="FCELL", rastname=r_output, overwrite=True) # Remove temporary files and reset mask if needed cleanup() # Set raster history to output raster grass.raster_history(r_output, overwrite=True) grass.run_command( "r.support", overwrite=True, map=r_output, title="Visual exposure index as {}".format(pfunction.replace("_", " ")), description="generated by r.viewshed.exposure", units="Index value", quiet=True, )