Skyview
source module isofit.utils.skyview
Functions
-
skyview — Applies sky view factor calculation for a given projected DEM or DSM. Much of this code was borrowed from ARS Topo-Calc. The key thing here was to create a python-only, rasterio-free port of this that could be used within ISOFIT. We also included improvements that are current in Jeff Dozier's horizon method in Matlab (https://github.com/DozierJeff/Topographic-Horizons). Following suggestions from Dozier (2021), multiprocessing is leveraged here w.r.t. to n_angles rotating the image. As default, sky view is computed with n angles = 64 which in most cases is of sufficient accuracy to resolve but more angles may be used.
-
horizon_worker — Each worker gets an angle and is sent to this function to compute horizons, and save to a compressed/scaled netcdf file.
-
save_horizon — utility function to house metadata and information for saving horizon angles
-
load_horizon — load horizon netcdf in for skyview calc using scale factors defined in save.
-
create_shadow_mask — Computes horizons at a specific geometry to create a binary shadow mask because nearby terrain can cast shadows onto pixels as a function of the solar geometry that aren't always captured in cos-i. In this case, the input angle is the solar azimuth, and the solar zenith is compared to h at each pixel.
-
gradient_d8 — Calculate the slope and aspect for provided dem, using a 3x3 cell around the center
-
calc_slope — Calculate the slope given the finite differences
-
aspect — Calculate the aspect from the finite difference. Aspect is degrees clockwise from North (0/360 degrees)
-
aspect_to_ipw_radians — IPW defines aspect differently than most GIS programs so convert an aspect in degrees from due North (0/360) to the IPW definition.
-
horizon — Calculate horizon angles for one direction. Horizon angles are based on Dozier and Frew 1990 and are adapted from the IPW C code.
-
adjust_spacing — Adjust the grid spacing if a skew angle is present
-
skew — Skew the origin of successive lines by a specified angle A skew with angle of 30 degrees causes the following transformation:
-
skew_transpose — Skew and transpose the dem for the given angle. Also calculate the new spacing given the skew.
-
transpose_skew — Transpose, skew then transpose a dem for the given angle. Also calculate the new spacing
source skyview(input: str, output_directory: str, resolution: float = np.nan, obs_or_loc: str = None, method: str = 'slope', n_angles: int = 64, logging_level: str = 'INFO', log_file: str = None, n_cores: int = 1, keep_horizon_files: bool = False, ray_address: str = None, ray_redis_password: str = None, ray_temp_dir: str = None, ray_ip_head: str = None)
Applies sky view factor calculation for a given projected DEM or DSM. Much of this code was borrowed from ARS Topo-Calc. The key thing here was to create a python-only, rasterio-free port of this that could be used within ISOFIT. We also included improvements that are current in Jeff Dozier's horizon method in Matlab (https://github.com/DozierJeff/Topographic-Horizons). Following suggestions from Dozier (2021), multiprocessing is leveraged here w.r.t. to n_angles rotating the image. As default, sky view is computed with n angles = 64 which in most cases is of sufficient accuracy to resolve but more angles may be used.
Optionally to this horizon based method, one can pass method="slope" to compute a faster estimate that may be sufficent for regions with lower relief. The slope based estimate is simply, svf = cos^2(slope/2).
Yet another option is to pass an ISOFIT "OBS" or "LOC" file as input and using the obs_or_loc arg. OBS files have slope data and can be used for method='slope' only. LOC files have elevation data and can be used for method='slope'. One can also use the full horizon method on the LOC file although this is not recommended because the edges miss information (a warning will be triggered in this case).
Parameters
input : str
Path to the projected ENVI File. If obs_or_loc is None or "loc" input is elevation. If is "obs", then it's a slope product.
output_directory : str
Directory path for temporary files and outputs during processing; similar to apply_oe.
resolution : float, optional
Spatial resolution of the projected DEM in coordinate units (GSD in meters). Required for elevation input data.
obs_or_loc : str, optional
Options here are 'obs', 'loc', or None. Default is None. If 'obs' is selected, it will pick the slope data from index 6 in OBS file.
If 'loc' is selected it well select the elevation data from index 2. None will assume a single band elevation data is passed.
method : str, optional
Options are either "horizon" or "slope". Passing "horizon" runs the full computation and is recommended for very steep terrain.
Passing "slope"" runs the simplifed calculation of svf=cos^2(slope/2) and can be useful for more mild slopes.
n_angles : int, optional
Number of angles used in horizon calculations (default is 64).
As a reference, n=72 computes every 5deg, n=64 every 5.6deg, n=32 every 11.25deg, etc.
keep_horizon_files : bool, optional
Horizon angles are created in output_dir as netcdfs. False deletes files, and True keeps them. These angles are based from zenith.
logging_level : str, optional
Logging verbosity level (default is "INFO"); similar to apply_oe.
log_file : str or None, optional
File path to write logs; similar to apply_oe.
n_cores : int, optional
Number of CPU cores to use for parallel processing (default is 1). Only used for method="horizon".
Note: n_cores should ideally not be larger than n_angles.
Raises
-
TypeError
-
ValueError
source horizon_worker(angle, dem, spacing, aspect, tan_slope, output_directory, logging_level, log_file)
Each worker gets an angle and is sent to this function to compute horizons, and save to a compressed/scaled netcdf file.
source save_horizon(h, angle, output_directory)
utility function to house metadata and information for saving horizon angles
source load_horizon(file_path)
load horizon netcdf in for skyview calc using scale factors defined in save.
source create_shadow_mask(input: str, output_directory: str, resolution: float = np.nan, sza: float = np.nan, saa: float = np.nan, logging_level: str = 'INFO', log_file: str = None, n_cores: int = 1, ray_address: str = None, ray_redis_password: str = None, ray_temp_dir: str = None, ray_ip_head: str = None)
Computes horizons at a specific geometry to create a binary shadow mask because nearby terrain can cast shadows onto pixels as a function of the solar geometry that aren't always captured in cos-i. In this case, the input angle is the solar azimuth, and the solar zenith is compared to h at each pixel.
As of right now, this assumes solar azimuth is constant value (0-360deg). However, solar zenith (0-90deg) can vary by pixel.
Raises
-
ValueError
source update_h_for_local_topo(h, aspect, azimuth, tan_slope)
source load_input(input, resolution, obs_or_loc=None, method='slope')
Raises
-
FileNotFoundError
-
ValueError
source gradient_d8(dem, dx, dy, aspect_rad=False)
Calculate the slope and aspect for provided dem, using a 3x3 cell around the center
Given a center cell e and it's neighbors:
| a | b | c | | d | e | f | | g | h | i |
The rate of change in the x direction is
[dz/dx] = ((c + 2f + i) - (a + 2d + g) / (8 * dx)
The rate of change in the y direction is
[dz/dy] = ((g + 2h + i) - (a + 2b + c)) / (8 * dy)
The slope is calculated
slope_radians = arctan ( sqrt ([dz/dx]^2 + [dz/dy]^2) )
Parameters
-
dem — array of elevation values
-
dx — cell size along the x axis
-
dy — cell size along the y axis
-
aspect_rad — turn the aspect from degrees to IPW radians
Returns
-
slope in radians aspect in degrees or IPW radians
source calc_slope(dz_dx, dz_dy)
Calculate the slope given the finite differences
Parameters
-
dz_dx — finite difference in the x direction
-
dz_dy — finite difference in the y direction
Returns
-
slope numpy array
Calculate the aspect from the finite difference. Aspect is degrees clockwise from North (0/360 degrees)
See below for a referance to how ArcGIS calculates slope http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/How_Aspect_works/00q900000023000000/
Parameters
-
dz_dx — finite difference in the x direction
-
dz_dy — finite difference in the y direction
Returns aspect in degrees clockwise from North
source aspect_to_ipw_radians(a)
IPW defines aspect differently than most GIS programs so convert an aspect in degrees from due North (0/360) to the IPW definition.
Aspect is radians from south (aspect 0 is toward the south) with range from -pi to pi, with negative values to the west and positive values to the east
Parameters
-
a — aspect in degrees from due North
Returns a: aspect in radians from due South
source horizon(azimuth, dem, spacing, par=False, n_cores=1)
Calculate horizon angles for one direction. Horizon angles are based on Dozier and Frew 1990 and are adapted from the IPW C code.
The coordinate system for the azimuth is 0 degrees is South, with positive angles through East and negative values through West. Azimuth values must be on the -180 -> 0 -> 180 range.
Parameters
-
azimuth {float} -- find horizon's along this direction
-
dem {np.array2d} -- numpy array of dem elevations
-
spacing {float} -- grid spacing
Returns
-
hcos {np.array} -- cosines of angles to the horizon
Raises
-
ValueError
source hor2d(z, delta, fwd=True, par=False, n_cores=1)
Raises
-
ValueError
source adjust_spacing(spacing, skew_angle)
Adjust the grid spacing if a skew angle is present
Parameters
-
spacing {float} -- grid spacing
-
skew_angle {float} -- angle to adjust the spacing for [degrees]
Raises
-
ValueError
source skew(arr, angle, fwd=True, fill_min=True)
Skew the origin of successive lines by a specified angle A skew with angle of 30 degrees causes the following transformation:
+-----------+ +---------------+
| | |000/ /|
| input | |00/ output /0|
| image | |0/ image /00|
| | |/ /000|
+-----------+ +---------------+
Calling skew with fwd=False will return the output image back to the input image.
Skew angle must be between -45 and 45 degrees
Parameters
-
arr — array to skew
-
angle — angle between -45 and 45 to skew by
-
fwd — add skew to image if True, unskew image if False
-
fill_min — While IPW skew says it fills with zeros, the output image is filled with the minimum value
Returns
-
skewed array
Raises
-
ValueError
source skew_transpose(dem, spacing, angle)
Skew and transpose the dem for the given angle. Also calculate the new spacing given the skew.
Parameters
-
dem {array} -- numpy array of dem elevations
-
spacing {float} -- grid spacing
-
angle {float} -- skew angle
Returns
-
t -- skew and transpose array spacing -- new spacing adjusted for angle
source transpose_skew(dem, spacing, angle)
Transpose, skew then transpose a dem for the given angle. Also calculate the new spacing
Parameters
-
dem {array} -- numpy array of dem elevations
-
spacing {float} -- grid spacing
-
angle {float} -- skew angle
Returns
-
t -- skew and transpose array spacing -- new spacing adjusted for angle