Source code for honeybee_plus.radiance.command.rfluxmtx

# coding=utf-8

from ._commandbase import RadianceCommand
from ..datatype import RadiancePath, RadianceValue, RadianceNumber
from ..datatype import RadianceBoolFlag
from ..parameters.rfluxmtx import RfluxmtxParameters

import os


# TODO (sarith and mostapha): move parameters such as output_data_format to command
# parameters. They are not command inputs.
[docs]class Rfluxmtx(RadianceCommand): """Radiance Rfluxmtx matrix.""" ground_string = """ void glow ground_glow 0 0 4 1 1 1 0 ground_glow source ground 0 0 4 0 0 -1 180 """ sky_string = """ void glow sky_glow 0 0 4 1 1 1 0 sky_glow source sky 0 0 4 0 0 1 180 """
[docs] @staticmethod def control_parameters(hemi_type='u', hemi_up_direction='Y', output_file=''): """Rfluxmtx ControlParameters.""" return RfluxmtxControlParameters(hemi_type, hemi_up_direction, output_file)
[docs] @staticmethod def default_sky_ground(file_name, sky_type=None, sky_file_format=None, ground_file_format=None): """ Args: file_name:This should be the name of the file to which the sky defintion should be written to. sky_type:The acceptable inputs for hemisphere type are: u for uniform.(Usually applicable for ground).\n kf for klems full.\n kh for klems half.\n kq for klems quarter.\n rN for Reinhart - Tregenza type skies. N stands for subdivisions and defaults to 1.\n scN for shirley-chiu subdivisions. Returns: file_name: Passes back the same file_name that was provided as input. """ sky_param = Rfluxmtx.control_parameters(hemi_type=sky_type or 'r', output_file=sky_file_format) ground_param = Rfluxmtx.control_parameters(hemi_type='u', output_file=ground_file_format) ground_string = Rfluxmtx.add_control_parameters(Rfluxmtx.ground_string, {'ground_glow': ground_param}) sky_string = Rfluxmtx.add_control_parameters(Rfluxmtx.sky_string, {'sky_glow': sky_param}) with open(file_name, 'w')as skyFile: skyFile.write(ground_string + '\n' + sky_string) return file_name
[docs] @staticmethod def add_control_parameters(input_string, modifier_dict): if os.path.exists(input_string): with open(input_string)as fileString: file_data = fileString.read() else: file_data = input_string output_string = '' check_dict = dict.fromkeys(modifier_dict.keys(), None) for lines in file_data.split('\n'): for key, value in modifier_dict.items(): if key in lines and not check_dict[key] and \ not lines.strip().startswith('#'): output_string += str(value) + '\n' check_dict[key] = True else: output_string += lines.strip() + '\n' for key, value in check_dict.items(): assert value, "The modifier %s was not found in the string specified" % key if os.path.exists(input_string): new_output_file = input_string[:-4] + '_cp_added' + input_string[-4:] with open(new_output_file, 'w') as newoutput: newoutput.write(output_string) output_string = new_output_file return output_string
[docs] @staticmethod def check_for_rflux_parameters(file_val): with open(file_val)as rfluxFile: rflux_string = rfluxFile.read() assert '#@rfluxmtx' in rflux_string, \ "The file %s does not have any rfluxmtx control parameters." return True
# sender = RadiancePath('sender','sender file') receiver_file = RadiancePath('receiver', 'receiver file') octree_file = RadiancePath('octree', 'octree file', extension='.oct') output_matrix = RadiancePath('output_matrix', 'output Matrix File') view_rays_file = RadiancePath('view_rays_file', 'file containing ray samples generated by vwrays') output_data_format = RadianceValue('f', 'output data format', is_joined=True) verbose = RadianceBoolFlag('v', 'verbose commands in stdout') num_processors = RadianceNumber('n', 'number of processors', num_type=int) # TODO: This method misses RfluxmtxParameters as an input. def __init__(self, sender=None, receiver_file=None, octree_file=None, rad_files=None, points_file=None, output_matrix=None, view_rays_file=None, view_info_file=None, output_filename_format=None, num_processors=None): RadianceCommand.__init__(self) self.sender = sender """Sender file will be either a rad file containing rfluxmtx variables or just a - """ self.receiver_file = receiver_file """Receiver file will usually be the sky file containing rfluxmtx variables""" self.octree_file = octree_file """Octree file containing the other rad file in the scene.""" self.rad_files = rad_files """Rad files other than the sender and receiver that are a part of the scene.""" self.points_file = points_file """The points file or input vwrays for which the illuminance/luminance value are to be calculated.""" self.number_of_points = 0 """Number of test points. Initially set to 0.""" self.output_matrix = output_matrix """The flux matrix file that will be created by rfluxmtx.""" self.view_rays_file = view_rays_file """File containing ray samples generated from vwrays""" self.view_info_file = view_info_file """File containing view dimensions calculated from vwrays.""" self.output_filename_format = output_filename_format """Filename format""" self.num_processors = num_processors """Number of processors""" @property def output_filename_format(self): return self._output_filename_format @output_filename_format.setter def output_filename_format(self, value): # TODO: Add testing logic for this ! self._output_filename_format = value or None @property def view_info_file(self): return self._view_info_file @view_info_file.setter def view_info_file(self, file_name): """ The input for this setter is a file containing the view dimensions calculated through the -d option in rfluxmtx. """ if file_name: assert os.path.exists(file_name),\ "The file %s specified as view_info_file does not exist." % file_name self._view_info_file = file_name with open(file_name) as view_fileName: self._view_fileDimensions = view_fileName.read().strip() else: self._view_info_file = '' self._view_fileDimensions = '' @property def points_file(self): return self._points_file @points_file.setter def points_file(self, value): if value: if os.path.exists(value): with open(value, 'rb') as pfile: self.number_of_points = sum(1 for line in pfile if line.strip()) elif self.number_of_points == 0: print('Warning: Failed to find the points_file at "{}".' ' Use number_of_points method to set the number_of_points' 'separately.') self._points_file = value else: self._points_file = '' @property def rad_files(self): """Get and set scene files.""" return self.__rad_files @rad_files.setter def rad_files(self, files): if files: self.__rad_files = [os.path.normpath(f) for f in files] else: self.__rad_files = [] @property def rfluxmtx_parameters(self): return self.__rfluxmtx_parameters @rfluxmtx_parameters.setter def rfluxmtx_parameters(self, parameters): self.__rfluxmtx_parameters = parameters or RfluxmtxParameters() assert hasattr(self.rfluxmtx_parameters, "isRfluxmtxParameters"), \ "input rfluxmtx_parameters is not a valid parameters type."
[docs] def to_rad_string(self, relative_path=False): octree = self.octree_file.to_rad_string() octree = '-i %s' % self.normspace(octree) if octree else '' output_data_format = self.output_data_format.to_rad_string() verbose = self.verbose.to_rad_string() number_of_processors = self.num_processors.to_rad_string() number_of_points = '-y %s' % self.number_of_points \ if self.number_of_points > 0 else '' points_file = self.normspace(self.points_file) points_file = '< %s' % points_file if points_file else '' view_file_samples = self.normspace(self.view_rays_file.to_rad_string()) view_file_samples = '< %s' % view_file_samples if view_file_samples else '' assert not (points_file and view_file_samples),\ 'View file and points file cannot be specified at the same time!' input_rays = points_file or view_file_samples output_matrix = self.normspace(self.output_matrix.to_rad_string()) output_matrix = "> %s" % output_matrix if output_matrix else '' output_filename_format = self.output_filename_format output_filename_format = "-o %s" % output_filename_format if \ output_filename_format else '' # method for adding an input or nothing to the command def add_to_str(val): return "%s " % val if val else '' # Creating the string this way because it might change again in the # future. rad_string = ["%s " % self.normspace(os.path.join(self.radbin_path, 'rfluxmtx'))] rad_string.append(add_to_str(output_data_format)) rad_string.append(add_to_str(verbose)) rad_string.append(add_to_str(number_of_processors)) rad_string.append(add_to_str(number_of_points)) rad_string.append(add_to_str(self._view_fileDimensions)) if str(self.sender).strip() == '-': rad_string.append(add_to_str(self.rfluxmtx_parameters.to_rad_string())) else: # -I and -i options are only valid for pass-through cases rflux_par = add_to_str( self.rfluxmtx_parameters.to_rad_string()).replace( '-I', '') rad_string.append(rflux_par) rad_string.append(add_to_str(output_filename_format)) rad_string.append(add_to_str(self.sender)) rad_string.append(add_to_str(self.normspace(self.receiver_file.to_rad_string()))) rad_string.append(add_to_str(" ".join(self.rad_files))) rad_string.append(add_to_str(octree)) rad_string.append(add_to_str(input_rays)) rad_string.append(add_to_str(output_matrix)) return ''.join(rad_string)
@property def input_files(self): return [self.receiver_file] + self.rad_files
[docs]class RfluxmtxControlParameters(object): """Rfluxmtx ControlParameters. Set the values for hemispheretype, hemisphere up direction and output file location (optional). """ def __init__(self, hemi_type='u', hemi_up_direction='Y', output_file=''): """Init class.""" self.hemisphere_type = hemi_type """ The acceptable inputs for hemisphere type are: u for uniform.(Usually applicable for ground). kf for klems full. kh for klems half. kq for klems quarter. rN for Reinhart - Tregenza type skies. N stands for subdivisions and defaults to 1. scN for shirley-chiu subdivisions.""" self.hemisphere_up_direction = hemi_up_direction """The acceptable inputs for hemisphere direction are %s""" % \ (",".join(('X', 'Y', 'Z', 'x', 'y', 'z', '-X', '-Y', '-Z', '-x', '-y', '-z'))) self.output_file = output_file @property def hemisphere_type(self): return self._hemisphereType @hemisphere_type.setter def hemisphere_type(self, value): """Hemisphere type. The acceptable inputs for hemisphere type are: u for uniform.(Usually applicable for ground). kf for klems full. kh for klems half. kq for klems quarter. rN for Reinhart - Tregenza type skies. N stands for subdivisions and defaults to 1. scN for shirley-chiu subdivisions. """ if value: if value in ('u', 'kf', 'kh', 'kq'): self._hemisphereType = value return elif value.startswith('r'): if len(value) > 1: try: num = int(value[1:]) except ValueError: raise Exception( "The format reinhart tregenza type skies is rN ." "The value entered was %s" % value) else: num = '' self._hemisphereType = 'r' + str(num) elif value.startswith('sc'): if len(value) > 2: try: num = int(value[2:]) except ValueError: raise Exception( "The format for ShirleyChiu type values is scN." "The value entered was %s" % value) else: raise Exception( "The format for ShirleyChiu type values is scN." "The value entered was %s" % value) self._hemisphereType = 'sc' + str(num) else: except_str = """ The acceptable inputs for hemisphere type are: u for uniform.(Usually applicable for ground). kf for klems full. kh for klems half. kq for klems quarter. rN for Reinhart - Tregenza type skies. N stands for subdivisions and defaults to 1. scN for shirley-chiu subdivisions. The value entered was %s """ % (value) raise Exception(except_str) @property def hemisphere_up_direction(self): return self._hemisphere_upDirection @hemisphere_up_direction.setter def hemisphere_up_direction(self, value): """hemisphere direction. The acceptable inputs for hemisphere direction are a tuple with 3 values or 'X', 'Y', 'Z', 'x', 'y', 'z', '-X', '-Y','-Z', '-x', '-y','-z'. """ allowed_values = ('X', 'Y', 'Z', 'x', 'y', 'z', '-X', '-Y', '-Z', '-x', '-y', '-z', "+X", "+Y", "+Z", '+x', "+y", "+z") if isinstance(value, (tuple, list)): assert len(value) == 3, \ 'Length of emisphereUpDirection vector should be 3.' self._hemisphere_upDirection = ','.join((str(v) for v in value)) elif value: assert value in allowed_values, "The value for hemisphere_upDirection" \ "should be one of the following: %s" \ % (','.join(allowed_values)) self._hemisphere_upDirection = value else: self._hemisphere_upDirection = '+Z' def __str__(self): output_file_spec = "o=%s" % self.output_file if self.output_file else '' return "#@rfluxmtx h=%s u=%s %s" % (self.hemisphere_type, self.hemisphere_up_direction, output_file_spec)