Source code for honeybee_radiance_postprocess.util
"""Post-processing utility functions."""
from typing import Tuple
import numpy as np
from honeybee_radiance.writer import _filter_by_pattern
[docs]
def binary_mtx_dimension(filepath: str) -> Tuple[int, int, int, int, str]:
"""Return binary Radiance matrix dimensions if exist.
This function returns NROWS, NCOLS, NCOMP and number of header lines including the
white line after last header line.
Args:
filepath: Full path to Radiance file.
Returns:
nrows, ncols, ncomp, line_count, fmt
"""
try:
inf = open(filepath, 'rb', encoding='utf-8')
except Exception:
inf = open(filepath, 'rb')
try:
first_line = next(inf).rstrip().decode('utf-8')
if first_line[:10] != '#?RADIANCE':
error_message = (
f'File with Radiance header must start with #?RADIANCE not '
f'{first_line}.'
)
raise ValueError(error_message)
header_lines = [first_line]
nrows = ncols = ncomp = None
for line in inf:
line = line.rstrip().decode('utf-8')
header_lines.append(line)
if line[:6] == 'NROWS=':
nrows = int(line.split('=')[-1])
if line[:6] == 'NCOLS=':
ncols = int(line.split('=')[-1])
if line[:6] == 'NCOMP=':
ncomp = int(line.split('=')[-1])
if line[:7] == 'FORMAT=':
fmt = line.split('=')[-1]
break
if not nrows or not ncols:
error_message = (
f'NROWS or NCOLS was not found in the Radiance header. NROWS '
f'is {nrows} and NCOLS is {ncols}. The header must have both '
f'elements.'
)
raise ValueError(error_message)
return nrows, ncols, ncomp, len(header_lines) + 1, fmt
finally:
inf.close()
[docs]
def check_array_dim(array: np.ndarray, dim: int):
"""Check NumPy array dimension.
Args:
array: A NumPy array.
dim: The dimension to check against.
"""
assert array.ndim == dim, \
f'Expected {dim}-dimensional array. Dimension of array is {array.ndim}'
[docs]
def filter_array(array: np.ndarray, mask: np.ndarray) -> np.ndarray:
"""Filter a NumPy array by a masking array. The array will be passed as is
if the mask is None.
Args:
array: A NumPy array to filter.
mask: A NumPy array of ones/zeros or True/False.
Returns:
A filtered NumPy array.
"""
if mask is not None:
return array[mask.astype(bool)]
return array
[docs]
def hoys_mask(sun_up_hours: list, hoys: list) -> np.ndarray:
"""Create a NumPy masking array from a list of hoys.
Args:
sun_up_hours: A list of sun up hours.
hoys: A list hoys to select.
Returns:
A NumPy array of booleans.
"""
if len(hoys) != 0:
hoys_mask = np.where(np.isin(sun_up_hours, hoys), True, False)
return hoys_mask
[docs]
def array_memory_size(
sensors: int, sun_up_hours: int, ncomp: int = None,
dtype: np.dtype = np.float32, gigabyte: bool = True) -> float:
"""Calculate the memory size of an array before creating or loading an
array.
Args:
sensors: Number of sensors in the array.
sun_up_hours: Number of sun up hours in the array.
ncomp: Optional number of components for each element in the array,
e.g., if the data is in RGB format then this value must be set
to 3. Defaults to None.
dtype: The data type of the array. Defaults to np.float32.
gigabyte: Boolean toggle to output the memory size in gigabytes.
Defaults to True.
Returns:
float: The memory size of an array.
"""
# check if dtype is valid
dtypes = tuple(np.sctypes['float'])
if not isinstance(dtype, dtypes):
try:
dtype = dtype()
except TypeError as err:
error_message = (
f'Unable to instantiate input dtype. Expected any of the '
f'following: {dtypes}. Received: {type(dtype)}.'
)
raise TypeError(error_message) from err
# calculate memory size
size = sensors * sun_up_hours * dtype.itemsize
if ncomp:
size *= ncomp
if gigabyte:
size /= (1024 ** 3)
return size
[docs]
def recursive_dict_merge(dict_1: dict, dict_2: dict):
"""Recursive merging of two dictionaries.
Args:
dict_1: Original dictionary.
dict_2: Dictionary to merge with dict_1.
"""
for k in dict_2:
if (k in dict_1 and isinstance(dict_1[k], dict) and
isinstance(dict_2[k], dict)):
recursive_dict_merge(dict_1[k], dict_2[k])
else:
dict_1[k] = dict_2[k]
def _filter_grids_by_pattern(grids_info, filter_pattern):
"""Filter grids_info by a pattern.
Args:
grids_info: Grid information.
filter_pattern: Pattern to filter grids by.
Returns:
A list of filtered grids.
"""
grids = _filter_by_pattern(grids_info, filter=filter_pattern)
return grids
[docs]
def get_delimiter(delimiter_input):
if delimiter_input == 'tab' or delimiter_input == '\t':
return '\t'
elif delimiter_input == 'space' or delimiter_input == ' ':
return ' '
elif delimiter_input == 'comma' or delimiter_input == ',':
return ','
elif delimiter_input == 'semicolon' or delimiter_input == ';':
return ';'
else:
raise ValueError(f'Unsupported delimiter: {delimiter_input}')