def test_writer(): """Test creating a new folder.""" folder_path = r'./tests/assets/temp' shutil.rmtree(folder_path, ignore_errors=True) rad_folder = Folder(folder_path) rad_folder.write(folder_type=2, overwrite=True) assert os.path.isdir(rad_folder.folder) root_folder = rad_folder.model_folder(full=True) assert os.path.isdir(root_folder) subfolders = [ f for f in os.listdir(root_folder) if os.path.isdir(_as_posix(os.path.join(root_folder, f))) ] cfg_names = ['GRID', 'VIEW' ] + [k for k, v in config.minimal.items() if v is True] expected_subfolders = [rad_folder._get_folder_name(f) for f in cfg_names] assert len(subfolders) == len(expected_subfolders) for f in expected_subfolders: assert f in subfolders # try to remove the folder shutil.rmtree(folder_path, ignore_errors=True)
def test_reader_files(): radiance_folder = r'./tests/assets/project_folder' rad_folder = Folder(radiance_folder) assert rad_folder.has_aperture_group assert not rad_folder.has_dynamic_scene assert rad_folder.aperture_files() == [ 'model/aperture/aperture.mat', 'model/aperture/aperture.rad' ] assert rad_folder.aperture_files(black_out=True) == [ 'model/aperture/aperture.blk', 'model/aperture/aperture.rad' ] s_files = rad_folder.scene_files() e_files = [ 'model/scene/context.mat', 'model/scene/context.rad', 'model/scene/partition.mat', 'model/scene/partition.rad', 'model/scene/partition_glass.mat', 'model/scene/partition_glass.rad', 'model/scene/room_envelope.mat', 'model/scene/room_envelope.rad' ] assert s_files.index(e_files[1]) - s_files.index(e_files[0]) == 1 assert s_files.index(e_files[3]) - s_files.index(e_files[2]) == 1 assert s_files.index(e_files[5]) - s_files.index(e_files[4]) == 1 assert s_files.index(e_files[7]) - s_files.index(e_files[6]) == 1 s_files = rad_folder.scene_files(black_out=True) e_files = [ 'model/scene/context.blk', 'model/scene/context.rad', 'model/scene/partition.blk', 'model/scene/partition.rad', 'model/scene/partition_glass.blk', 'model/scene/partition_glass.rad', 'model/scene/room_envelope.blk', 'model/scene/room_envelope.rad' ] assert s_files.index(e_files[1]) - s_files.index(e_files[0]) == 1 assert s_files.index(e_files[3]) - s_files.index(e_files[2]) == 1 assert s_files.index(e_files[5]) - s_files.index(e_files[4]) == 1 assert s_files.index(e_files[7]) - s_files.index(e_files[6]) == 1
def test_aperture_group(): radiance_folder = r'./tests/assets/project_folder' folder = Folder(radiance_folder) apertures = folder.aperture_groups(interior=False) assert len(apertures) == 1 ap = apertures[0] assert ap.states[0].identifier == '0_clear' assert ap.states[0].default == 'south_window..default..000.rad' assert ap.states[1].identifier == '1_diffuse' assert ap.states[1].default == 'south_window..default..001.rad'
def create_octree_from_folder( folder, output, include_aperture, default, add_before, add_after, dry_run): """Generate a static octree from a folder. folder: Path to a Radiance model folder. """ model_folder = ModelFolder.from_model_folder(folder) try: black_out = False if default else True scene_files = model_folder.scene_files(black_out=black_out) if include_aperture: # no black out here aperture_files = model_folder.aperture_files() scene_files += aperture_files if add_after: scene_files += list(add_after) if add_before: scene_files = list(add_before) + scene_files cmd = Oconv(output=output, inputs=scene_files) cmd.options.f = True if dry_run: click.echo(cmd) else: env = None if folders.env != {}: env = folders.env env = dict(os.environ, **env) if env else None cmd.run(env=env, cwd=model_folder.folder) except Exception: _logger.exception('Failed to generate octree.') sys.exit(1) else: sys.exit(0)
def test_scene_mapping(): folder_path = r'./tests/assets/model_folders/simple/model' model_folder = Folder.from_model_folder(folder_path) # two phase scene_mapping = model_folder.octree_scene_mapping(exclude_static=False, phase=2) os.remove(r'./tests/assets/model_folders/simple/scene_mapping.json') assert 'two_phase' in scene_mapping assert 'three_phase' not in scene_mapping assert 'five_phase' not in scene_mapping assert len(scene_mapping['two_phase']) == 11 # three phase scene_mapping = model_folder.octree_scene_mapping(exclude_static=False, phase=3) os.remove(r'./tests/assets/model_folders/simple/scene_mapping.json') assert 'two_phase' in scene_mapping assert 'three_phase' in scene_mapping assert 'five_phase' not in scene_mapping assert len(scene_mapping['two_phase']) == 3 # five phase scene_mapping = model_folder.octree_scene_mapping(exclude_static=False, phase=5) os.remove(r'./tests/assets/model_folders/simple/scene_mapping.json') assert 'two_phase' in scene_mapping assert 'three_phase' in scene_mapping assert 'five_phase' in scene_mapping assert len(scene_mapping['two_phase']) == 3 assert len(scene_mapping['five_phase']) == 8
def test_grid_mapping(): folder_path = r'./tests/assets/model_folders/simple/model' model_folder = Folder.from_model_folder(folder_path) # two phase grid_mapping = model_folder.grid_mapping(exclude_static=False, phase=2) os.remove(r'./tests/assets/model_folders/simple/grid_mapping.json') assert 'two_phase' in grid_mapping assert 'three_phase' not in grid_mapping assert 'five_phase' not in grid_mapping assert len(grid_mapping['two_phase']) == 6 # three phase grid_mapping = model_folder.grid_mapping(exclude_static=False, phase=3) os.remove(r'./tests/assets/model_folders/simple/grid_mapping.json') assert 'two_phase' in grid_mapping assert 'three_phase' in grid_mapping assert 'five_phase' not in grid_mapping assert len(grid_mapping['two_phase']) == 2 assert len(grid_mapping['three_phase']) == 4 # five phase grid_mapping = model_folder.grid_mapping(exclude_static=False, phase=5) os.remove(r'./tests/assets/model_folders/simple/grid_mapping.json') assert 'two_phase' in grid_mapping assert 'three_phase' in grid_mapping assert 'five_phase' in grid_mapping assert len(grid_mapping['two_phase']) == 2 assert len(grid_mapping['three_phase']) == 4 assert len(grid_mapping['five_phase']) == 4
def test_scene_mapping_static_model(): folder_path = r'./tests/assets/model_folders/static/model' model_folder = Folder.from_model_folder(folder_path) # exclude static apertures scene_mapping = model_folder.grid_mapping(exclude_static=False, phase=5) os.remove(r'./tests/assets/model_folders/static/grid_mapping.json') assert len(scene_mapping['two_phase']) == 1 assert len(scene_mapping['three_phase']) == 0 assert len(scene_mapping['five_phase']) == 0 # do not exclude static apertures scene_mapping = model_folder.grid_mapping(exclude_static=True, phase=5) os.remove(r'./tests/assets/model_folders/static/grid_mapping.json') assert len(scene_mapping['two_phase']) == 0 assert len(scene_mapping['three_phase']) == 0 assert len(scene_mapping['five_phase']) == 0
def create_octree_from_folder_multiphase(folder, sun_path, phase, output_folder): """Generate a set of octrees from a folder. This command will generate octrees for both default and direct studies. It will do so for static apertures and aperture groups, creating one octree for each light path, i.e., all other light paths are blacked. \b Args: folder: Path to a Radiance model folder. """ model_folder = ModelFolder.from_model_folder(folder) # check if sunpath file exist - otherwise continue without it if sun_path and not os.path.isfile(sun_path): sun_path = None if phase == '5' and not sun_path: raise RuntimeError( 'To generate octrees for a 5 Phase study you must provide a sunpath.' ) phases = { '2': ['two_phase'], '3': ['two_phase', 'three_phase'], '5': ['two_phase', 'three_phase', 'five_phase'] } try: scene_mapping = model_folder.octree_scene_mapping() if not os.path.isdir(output_folder): os.mkdir(output_folder) octree_mapping = [] for study, states in scene_mapping.items(): if study not in phases[phase]: continue study_type = [] for state in states: info, commands = _generate_octrees_info( state, output_folder, study, sun_path) study_type.append(info) for cmd in commands: env = None if folders.env != {}: env = folders.env env = dict(os.environ, **env) if env else None cmd.run(env=env, cwd=model_folder.folder) octree_mapping.append({study: study_type}) octree_output = os.path.join( model_folder.folder, output_folder, '%s.json' % study ) with open(octree_output, 'w') as fp: json.dump(study_type, fp, indent=2) octree_output = os.path.join( model_folder.folder, output_folder, 'multi_phase.json' ) with open(octree_output, 'w') as fp: json.dump(octree_mapping, fp, indent=2) except Exception: _logger.exception('Failed to generate octrees.') sys.exit(1) else: sys.exit(0)
def create_octree_from_shade_trans_groups(folder, sun_path, output_folder): """Generate a set of octrees from a folder containing shade transmittance groups. This command assumes that each shade group in the radiance folder contains only two states. The first is a completely opaque representation of the shade group and the second is a completely transparent representation of the shade group. This abstracted representation is intended to simulate dynamic shade transmittance that changes at each timestep. Each shade group will get an octree. If a sun-path is provided, an additional octree will be added for each group. \b Args: folder: Path to a Radiance model folder. """ model_folder = ModelFolder.from_model_folder(folder) try: # first, check to see if there are any shade groups in the model output_folder = os.path.join(model_folder.folder, output_folder) if not os.path.isdir(output_folder): os.mkdir(output_folder) group_info_file = os.path.join(output_folder, 'trans_info.json') group_info, groups_exist = [], True try: grp_folder = model_folder.dynamic_scene_folder() shd_groups = model_folder.dynamic_scene() if len(shd_groups) == 0: groups_exist = False except Exception: groups_exist = False if groups_exist: # get the static scene files scene_files = model_folder.scene_files(black_out=False) try: aperture_files = model_folder.aperture_files(black_out=False) scene_files += aperture_files except Exception: pass # no apertures available in the model # get the environment variables env = None if folders.env != {}: env = folders.env env = dict(os.environ, **env) if env else None # loop through the shade groups and create the octrees for i, s_grp in enumerate(shd_groups): # gather files to represent the transparent shade group dyn_grp = [_model_rel(grp_folder, sg.states[0].default) for j, sg in enumerate(shd_groups) if j != i] dyn_grp = [sg.replace('\\', '/') for sg in dyn_grp] grp_scene_files = scene_files + dyn_grp oct_file = os.path.join(output_folder, '{}.oct'.format(s_grp.identifier)) # command for the octree cmds = [Oconv(output=oct_file, inputs=grp_scene_files)] # add info about the generated files grp_info_dict = { 'identifier': s_grp.identifier, 'default': os.path.basename(oct_file) } # command for the octree with suns if sun_path and os.path.isfile(sun_path): sun_file = os.path.join( output_folder, '{}_sun.oct'.format(s_grp.identifier)) sun_scene_files = [sun_path] + grp_scene_files cmd_ss = Oconv(output=sun_file, inputs=sun_scene_files) cmds.append(cmd_ss) grp_info_dict['sun'] = os.path.basename(sun_file) # run all of the commands to create the octrees for cmd in cmds: cmd.options.f = True cmd.run(env=env, cwd=model_folder.folder) group_info.append(grp_info_dict) # write out a JSON with information about the octrees and groups with open(group_info_file, 'w') as fp: json.dump(group_info, fp, indent=2) except Exception: _logger.exception('Failed to generate shade trans group octrees.') sys.exit(1) else: sys.exit(0)
def test_reader(): radiance_folder = r'./tests/assets/project_folder' rad_folder = Folder(radiance_folder) assert rad_folder.model_folder() == 'model' assert rad_folder.aperture_folder() == _as_posix( os.path.join('model', 'aperture')) assert rad_folder.aperture_group_folder() == \ _as_posix(os.path.join('model', 'aperture_group')) assert rad_folder.aperture_group_folder(interior=True) == \ _as_posix(os.path.join('model', 'aperture_group', 'interior')) assert rad_folder.bsdf_folder() == _as_posix(os.path.join('model', 'bsdf')) assert rad_folder.grid_folder() == _as_posix(os.path.join('model', 'grid')) assert rad_folder.ies_folder() == _as_posix(os.path.join('model', 'ies')) assert rad_folder.scene_folder() == _as_posix( os.path.join('model', 'scene')) assert rad_folder.dynamic_scene_folder() == \ _as_posix(os.path.join('model', 'scene_dynamic')) assert rad_folder.dynamic_scene_folder(indoor=True) == \ _as_posix(os.path.join('model', 'scene_dynamic', 'indoor')) assert rad_folder.view_folder() == _as_posix(os.path.join('model', 'view'))
import ifcopenshell from honeybee_plus.room import Room from honeybee_plus.radiance.material.glass import Glass from honeybee_plus.radiance.properties import RadianceProperties from honeybee_plus.radiance.sky.certainIlluminance import CertainIlluminanceLevel from honeybee_plus.radiance.recipe.pointintime.gridbased import GridBased from honeybee_radiance_folder import ModelFolder from honeybee_plus.hbsurface import HBSurface from honeybee_plus.hbfensurface import HBFenSurface from daylight_analysis_load_IFC_data import * import os from dataclasses import dataclass, InitVar # Set radiance result folder to "room" rf = "./room" folder = ModelFolder(rf) folder.write(overwrite=True) ######################################### ###CREATE WINDOWOUT AND SPACEOUT LISTS### ######################################### # Temporary variable for storing spaces out = [] # remove excel formatting for each space. for i in spaces: out.append(SpaceParams((spaceDims(i)), excelFormat=False).out) # remove empty space entries spaceOut = [x for x in out if x != []]
def test_grids(): project_folder = r'./tests/assets/project_folder' folder = Folder(project_folder) files = folder.grid_files(rel_path=True) assert 'model/grid/cubical.pts' in files assert 'model/grid/hallway.pts' in files
def prepare_multiphase_command(folder, grid_count, grid_divisor, min_sensor_count, sun_path, phase, octree_folder, grid_folder, exclude_static): """This command prepares the model folder for simulations with aperture groups. It will generate a set of octrees and sensor grids that are unique to each state of each aperture group. This command will generate octrees for both default and direct studies for aperture groups, creating one octree for each light path, i.e., all other light paths are blacked. Sensor grids will be redistributed if they are to be used in a two phase simulation. A subfolder for each light path will be created. In this folder the redistributed grids are found. If the model folder have aperture groups, a file with states information for each grid will be written. \b Args: folder: Path to a Radiance model folder. grid_count: Number of output sensor grids to be created. This number is usually equivalent to the number of processes that will be used to run the simulations in parallel. """ model_folder = ModelFolder.from_model_folder(folder) # check if sunpath file exist - otherwise continue without it if sun_path and not os.path.isfile(sun_path): sun_path = None phase = int(phase) if phase == 5 and not sun_path: raise RuntimeError( 'To generate octrees for a 5 Phase study you must provide a sunpath.' ) phases = { 2: ['two_phase'], 3: ['two_phase', 'three_phase'], 5: ['two_phase', 'three_phase', 'five_phase'] } def _get_grid_states(model_folder=model_folder): states_info = model_folder.aperture_groups_states() grid_info = model_folder.grid_info() grid_states = {} for grid in grid_info: grid_states[grid['identifier']] = {} light_paths = [lp[0] for lp in grid['light_path']] for light_path in light_paths: if light_path != 'static_apertures': grid_states[grid['identifier']][light_path] = \ [s['identifier'] for s in states_info[light_path]] grid_states_output = os.path.join(model_folder.folder, 'grid_states.json') with open(grid_states_output, 'w') as fp: json.dump(grid_states, fp, indent=2) def _get_octrees_and_grids(model_folder=model_folder, grid_count=grid_count, phase=phase, octree_folder=octree_folder, grid_folder=grid_folder, exclude_static=exclude_static): scene_mapping = model_folder.octree_scene_mapping( exclude_static=exclude_static, phase=phase) if not os.path.isdir(octree_folder): os.mkdir(octree_folder) dynamic_mapping = [] for study, states in scene_mapping.items(): if study not in phases[phase]: continue if study == 'two_phase': grid_info_dict = {} grid_mapping = model_folder.grid_mapping( exclude_static=exclude_static, phase=phase) if not os.path.isdir(grid_folder): os.mkdir(grid_folder) grid_count = int(grid_count / grid_divisor) grid_count = 1 if grid_count < 1 else grid_count for light_path in grid_mapping['two_phase']: grid_info = light_path['grid'] output_folder = os.path.join(grid_folder, light_path['identifier']) _grid_count, _sensor_per_grid, out_grid_info = redistribute_sensors( model_folder.grid_folder(), output_folder, grid_count, min_sensor_count, grid_info=grid_info) grid_info_dict[light_path['identifier']] = out_grid_info study_type = [] for state in states: info, commands = _generate_octrees_info( state, octree_folder, study, sun_path) study_type.append(info) for cmd in commands: env = None if folders.env != {}: env = folders.env env = dict(os.environ, **env) if env else None cmd.run(env=env, cwd=model_folder.folder) # add grid information and folder if two_phase if study == 'two_phase': info['sensor_grids_folder'] = state['light_path'] info['sensor_grids_info'] = grid_info_dict[ state['light_path']] dynamic_mapping.append({study: study_type}) dynamic_output = os.path.join(model_folder.folder, '%s.json' % study) with open(dynamic_output, 'w') as fp: json.dump(study_type, fp, indent=2) dynamic_output = os.path.join(model_folder.folder, 'multi_phase.json') with open(dynamic_output, 'w') as fp: json.dump(dynamic_mapping, fp, indent=2) try: if model_folder.has_aperture_group or not exclude_static: _get_octrees_and_grids(model_folder=model_folder, grid_count=grid_count, phase=phase, octree_folder=octree_folder, grid_folder=grid_folder, exclude_static=exclude_static) if model_folder.has_aperture_group: _get_grid_states(model_folder=model_folder) else: # no aperture groups and static excluded, write empty files dynamic_mapping = [] for study in phases[phase]: study_type = [] dynamic_mapping.append({study: study_type}) dynamic_output = os.path.join(model_folder.folder, '%s.json' % study) with open(dynamic_output, 'w') as fp: json.dump(study_type, fp, indent=2) dynamic_output = os.path.join(model_folder.folder, 'multi_phase.json') with open(dynamic_output, 'w') as fp: json.dump(dynamic_mapping, fp, indent=2) except Exception: _logger.exception('Failed to generate octrees and grids.') sys.exit(1) else: sys.exit(0)
def dmtx_group_command( folder, octree, rflux_sky, name, size, threshold, ambient_division, output_folder, ): """Calculate aperture groups for daylight matrix purposes. This command calculates view factor from apertures to sky patches (rfluxmtx). Each aperture is represented by a sensor grid, and the view factor for the whole aperture is the average of the grid. The apertures are grouped based on the threshold. \b Args: folder: Path to a Radiance model folder. octree: Path to octree file. rflux_sky: Path to rflux sky file. """ def _index_and_min(distance_matrix): """Return the minimum value of the distance matrix, as well as the index [j, i] of the minimum value of the distance matrix.""" min_value = min([min(sublist) for sublist in distance_matrix]) for i, _i in enumerate(distance_matrix): for j, _j in enumerate(distance_matrix): if distance_matrix[i][j] == min_value: index = [j, i] break return min_value, index def _pairwise_maximum(array1, array2): """Return an array of the pairwise maximum of two arrays.""" pair_array = [array1, array2] max_array = list(map(max, zip(*pair_array))) return max_array def _tranpose_matrix(matrix): """Transposes the distance matrix.""" matrix = list(map(list, zip(*matrix))) return matrix def _rmse_from_matrix(input): """Calculates RMSE.""" rmse = [] for i, predicted in enumerate(input): r_list = [] for j, observed in enumerate(input): error = [(p - o) for p, o in zip(predicted, observed)] square_error = [e**2 for e in error] mean_square_error = sum(square_error) / len(square_error) root_mean_square_error = mean_square_error**0.5 r_list.append(root_mean_square_error) rmse.append(r_list) return rmse def _flatten(container): """Flatten an array.""" if not isinstance(container, list): container = [container] for i in container: if isinstance(i, (list, tuple)): for j in _flatten(i): yield j else: yield i def _agglomerative_clustering_complete(distance_matrix, ap_name, threshold=0.001): """Cluster apertures based on the threshold.""" # Fill the diagonal with 9999 so a diagonal of zeros will NOT be stored as min_value. for i in range(len(distance_matrix)): distance_matrix[i][i] = 9999 # Create starting list of aperture groups. Each aperture starts as its own group. ap_groups = ap_name # Set the number of samples and the minimum value of the distance matrix. n_samples = len(distance_matrix) # Set the minimum value of the distance matrix and find the indices of the minimum # value in the distance matrix. min_value, index = _index_and_min(distance_matrix) while n_samples > 1 and min_value < threshold: # Combine the two groups and place it at index 0, and remove item at index 1. ap_groups[index[0]] = [ap_groups[index[0]], ap_groups[index[1]]] ap_groups.pop(index[1]) # Update the values in the distance matrix. We need the maximum values between # the new cluster and all the remaining apertures or clusters still in the # distance matrix. distance_matrix[index[0]] = \ _pairwise_maximum(distance_matrix[index[0]], distance_matrix[index[1]]) distance_matrix = _tranpose_matrix(distance_matrix) distance_matrix[index[0]] = \ _pairwise_maximum(distance_matrix[index[0]], distance_matrix[index[1]]) # Remove the values at index 1 along both axes. distance_matrix.pop(index[1]) distance_matrix = _tranpose_matrix(distance_matrix) distance_matrix.pop(index[1]) # Update the number of samples that are left in the distance matrix. n_samples -= 1 # Update the minimum value and the indices. min_value, index = _index_and_min(distance_matrix) return ap_groups def _aperture_view_factor(project_folder, apertures, size=0.2, ambient_division=1000, receiver='rflux_sky.sky', octree='scene.oct', calc_folder='dmtx_aperture_grouping'): """Calculates the view factor for each aperture by sensor points.""" # Instantiate dictionary that will store the sensor count for each aperture. We need # a OrderedDict so that we can split the rfluxmtx output file by each aperture # (sensor count) in the correct order. ap_dict = OrderedDict() meshes = [] # Create a mesh for each aperture and add the the sensor count to dict. for aperture in apertures: ap_mesh = aperture.geometry.mesh_grid(size, flip=True, generate_centroids=False) meshes.append(ap_mesh) ap_dict[aperture.display_name] = { 'sensor_count': len(ap_mesh.faces) } # Create a sensor grid from joined aperture mesh. grid_mesh = SensorGrid.from_mesh3d('aperture_grid', Mesh3D.join_meshes(meshes)) # Write sensor grid to pts file. sensors = grid_mesh.to_file(os.path.join(project_folder, calc_folder), file_name='apertures') # rfluxmtx options rfluxOpt = RfluxmtxOptions() rfluxOpt.ad = ambient_division rfluxOpt.lw = 1.0 / float(rfluxOpt.ad) rfluxOpt.I = True rfluxOpt.h = True # rfluxmtx command rflux = Rfluxmtx() rflux.options = rfluxOpt rflux.receivers = receiver rflux.sensors = sensors rflux.octree = octree rflux.output = os.path.join(calc_folder, 'apertures_vf.mtx') # Run rfluxmtx command rflux.run(cwd=project_folder) # Get the output file of the rfluxmtx command. mtx_file = os.path.join(project_folder, rflux.output) return mtx_file, ap_dict try: model_folder = ModelFolder.from_model_folder(folder) apertures = [] states = model_folder.aperture_groups_states(full=True) ap_group_folder = model_folder.aperture_group_folder(full=True) for ap_group in states.keys(): if 'dmtx' in states[ap_group][0]: mtx_file = os.path.join( ap_group_folder, os.path.basename(states[ap_group][0]['dmtx'])) polygon_string = parse_from_file(mtx_file) polygon = Polygon.from_string('\n'.join(polygon_string)) apertures.append( Aperture.from_vertices(ap_group, polygon.vertices)) assert len(apertures) != 0, \ 'Found no valid dynamic apertures. There should at least be one aperture ' \ 'with transmittance matrix in your model.' # Calculate view factor. mtx_file, ap_dict = _aperture_view_factor( model_folder.folder, apertures, size=size, ambient_division=ambient_division, receiver=rflux_sky, octree=octree, calc_folder=output_folder) view_factor = [] # Read view factor file, convert to one channel output, and divide by Pi. with open(mtx_file) as mtx_data: for sensor in mtx_data: sensor_split = sensor.strip().split() if len(sensor_split) % 3 == 0: one_channel = sensor_split[::3] convert_to_vf = lambda x: float(x) / math.pi view_factor.append(list(map(convert_to_vf, one_channel))) ap_view_factor = [] # Split the view factor file by the aperture sensor count. for aperture in ap_dict.values(): sensor_count = aperture['sensor_count'] ap_vf, view_factor = view_factor[:sensor_count], view_factor[ sensor_count:] ap_view_factor.append(ap_vf) ap_view_factor_mean = [] # Get the mean view factor per sky patch for each aperture. for aperture in ap_view_factor: ap_t = _tranpose_matrix(aperture) ap_view_factor_mean.append( [sum(sky_patch) / len(sky_patch) for sky_patch in ap_t]) # Calculate RMSE between all combinations of averaged aperture view factors. rmse = _rmse_from_matrix(ap_view_factor_mean) ap_name = list(ap_dict.keys()) # Cluster the apertures by the 'complete method'. ap_groups = _agglomerative_clustering_complete(rmse, ap_name, threshold) # Flatten the groups. This will break the intercluster structure, but we do not need # to know that. ap_groups = [list(_flatten(cluster)) for cluster in ap_groups] # Add the aperture group to each aperture in the dictionary and write the aperture # group rad files. group_names = [] groups_folder = os.path.join(model_folder.folder, output_folder, 'groups') if not os.path.isdir(groups_folder): os.mkdir(groups_folder) for idx, group in enumerate(ap_groups): group_name = "group_{}".format(idx) group_file = os.path.join(groups_folder, group_name + '.rad') xform = [] group_names.append({ 'identifier': group_name, 'aperture_groups': group }) for ap in group: xform.append( "!xform ./model/aperture_group/{}..mtx.rad".format(ap)) with open(group_file, "w") as file: file.write('\n'.join(xform)) # Write aperture dictionary to json file. output = os.path.join(model_folder.folder, output_folder, 'groups', '%s.json' % name) with open(output, 'w') as fp: json.dump(group_names, fp, indent=2) except Exception: _logger.exception("Failed to run dmtx-group command.") traceback.print_exc() sys.exit(1) else: sys.exit(0)
def create_octree_from_abstracted_groups(folder, sun_path, output_folder): """Generate a set of octrees from a folder containing abstracted aperture groups. This command assumes that each aperture group in the radiance folder contains only two states. The first is a 100 percent transmittance specular (or beam) representation of the aperture group and the second is a 100 percent transmittance diffuse representation of the aperture group. This abstracted representation is intended to simulate contributions of dynamic groups when an external source is able to provide specular and diffuse transmittances at each timestep. For example, EnergyPlus can provide such values, which together can account for several types of complex dynamic fenestration types. Each aperture group will get at least two octrees (one with specular and one with diffuse). If a sun-path is provided, a third octree will be added with the suns included. \b Args: folder: Path to a Radiance model folder. """ model_folder = ModelFolder.from_model_folder(folder) try: # first, check to see if there are any aperture groups in the model output_folder = os.path.join(model_folder.folder, output_folder) if not os.path.isdir(output_folder): os.mkdir(output_folder) group_info_file = os.path.join(output_folder, 'group_info.json') group_info, groups_exist = [], True try: grp_folder = model_folder.aperture_group_folder() ap_groups = model_folder.aperture_groups() if len(ap_groups) == 0: groups_exist = False except Exception: groups_exist = False if groups_exist: # get the static scene files with blacked-out apertures scene_files = model_folder.scene_files(black_out=False) try: aperture_files = model_folder.aperture_files(black_out=True) scene_files += aperture_files except Exception: pass # no apertures available in the model # get the environment variables env = None if folders.env != {}: env = folders.env env = dict(os.environ, **env) if env else None # loop through the aperture groups and create the octrees for i, a_grp in enumerate(ap_groups): # create a sub-folder and get black versions of all other aperture groups sub_folder = os.path.join(output_folder, a_grp.identifier) if not os.path.isdir(sub_folder): os.mkdir(sub_folder) blk_grp = [_model_rel(grp_folder, ag.states[0].black) for j, ag in enumerate(ap_groups) if j != i] blk_grp = [bg.replace('\\', '/') for bg in blk_grp] grp_scene_files = scene_files + blk_grp # command for the octree for specular transmittance spec_file = os.path.join(sub_folder, 'spec.oct') spec_scene_files = grp_scene_files + \ [_model_rel(grp_folder, a_grp.states[0].default)] cmd_s = Oconv(output=spec_file, inputs=spec_scene_files) # command for the octree for diffuse transmittance diff_file = os.path.join(sub_folder, 'diff.oct') diff_scene_files = grp_scene_files + \ [_model_rel(grp_folder, a_grp.states[1].default)] cmd_d = Oconv(output=diff_file, inputs=diff_scene_files) cmds = [cmd_s, cmd_d] # add info about the generated files grp_info_dict = { 'identifier': a_grp.identifier, 'spec': os.path.basename(spec_file), 'diff': os.path.basename(diff_file) } # command for the octree with suns if sun_path and os.path.isfile(sun_path): spec_sun_file = os.path.join(sub_folder, 'spec_sun.oct') spec_sun_scene_files = [sun_path] + spec_scene_files cmd_ss = Oconv(output=spec_sun_file, inputs=spec_sun_scene_files) cmds.append(cmd_ss) grp_info_dict['sun'] = os.path.basename(spec_sun_file) # run all of the commands to create the octrees for cmd in cmds: cmd.options.f = True cmd.run(env=env, cwd=model_folder.folder) group_info.append(grp_info_dict) # write out a JSON with information about the octrees and groups with open(group_info_file, 'w') as fp: json.dump(group_info, fp, indent=2) except Exception: _logger.exception('Failed to generate abstracted group octrees.') sys.exit(1) else: sys.exit(0)
def test_static_aperture(): radiance_folder = r'./tests/assets/project_folder' folder = Folder(radiance_folder) files = folder.aperture_files(black_out=False, rel_path=True) assert 'model/aperture/aperture.mat' in files assert 'model/aperture/aperture.rad' in files
def create_octree_from_folder( folder, output, default, include_aperture, black_groups, first_shade_state, include_ies, add_before, add_after, dry_run ): """Generate a static octree from a folder. \b Args: folder: Path to a Radiance model folder. """ model_folder = ModelFolder.from_model_folder(folder) try: black_out = False if default else True scene_files = model_folder.scene_files(black_out=black_out) if include_aperture: # no black out here try: aperture_files = model_folder.aperture_files() scene_files += aperture_files except Exception: pass # no apertures available in the model if black_groups: try: group_files = model_folder.aperture_group_files_black() scene_files += group_files except Exception: pass # no aperture groups available in the model if first_shade_state: try: dyn_folder = model_folder.dynamic_scene_folder(full=True) dyn_shades = model_folder.dynamic_scene() shd_g_files = [os.path.join(dyn_folder, grp.states[0].default) for grp in dyn_shades] scene_files += shd_g_files except Exception: pass # no shade groups available in the model if include_ies: try: ies_folder = model_folder.ies_folder() for fp in os.listdir(ies_folder): if fp.endswith('rad'): scene_files += os.path.join(ies_folder, fp) except Exception: pass # no aperture groups available in the model if add_after: scene_files += list(add_after) if add_before: scene_files = list(add_before) + scene_files cmd = Oconv(output=output, inputs=scene_files) cmd.options.f = True if dry_run: click.echo(cmd) else: env = None if folders.env != {}: env = folders.env env = dict(os.environ, **env) if env else None cmd.run(env=env, cwd=model_folder.folder) except Exception: _logger.exception('Failed to generate octree.') sys.exit(1) else: sys.exit(0)