def two_matrix_operations( first_mtx, second_mtx, operator, keep_header, conversion, output_mtx, output_format, dry_run ): """Operations between two Radiance matrices. \b args: first-mtx: Path to fist matrix. second-mtx: Path to second matrix. """ try: cmd = 'rmtxop -f{output_format} "{first_mtx}" {operator} "{second_mtx}"'.format( output_format=output_format, first_mtx=first_mtx, operator=handle_operator(operator), second_mtx=second_mtx ) if conversion and conversion.strip(): cmd = cmd + ' -c {conversion}'.format(conversion=conversion) if not keep_header: cmd = cmd + ' | getinfo - ' if output_mtx: cmd = cmd + ' > "%s"' % output_mtx if dry_run: click.echo(cmd) sys.exit(0) run_command(cmd, env=folders.env) except Exception: _logger.exception('Operation on two Radiance matrix failed.') sys.exit(1) else: sys.exit(0)
def three_phase_calc(sky_vector, view_matrix, t_matrix, daylight_matrix, output_matrix, options, dry_run): """Matrix multiplication for view matrix, transmission matrix, daylight matrix and sky matrix.""" try: base_options = DctimestepOptions() options = options.strip() if options else None if options: base_options.update_from_string(options) cmd = Dctimestep.three_phase_calc(sky_vector=sky_vector, view_matrix=view_matrix, t_matrix=t_matrix, daylight_matrix=daylight_matrix, output=output_matrix, options=base_options) if dry_run: click.echo(cmd) else: run_command(cmd.to_radiance(), env=folders.env) except OSError: os.system(cmd.to_radiance()) except Exception: _logger.exception( 'Failed to run matrix multiplication calculations with ' 'dctimestep') sys.exit(1) else: sys.exit(0)
def sunpath_from_wea_rad(wea, north, sky_type, sky_density, output_format, hourly, visible, all_hours, folder, name, log_file, dry_run): """Generate a climate-based sky matrix from a Wea file using radiance's gendaymtx. \b Args: wea: Path to a wea file. """ try: if not os.path.exists(folder): os.makedirs(folder) output = os.path.join(folder, '%s.mtx' % name) opt = GendaymtxOptions() opt.r = north opt.O = '0' if visible else '1' if sky_type == 'total': pass elif sky_type == 'sun-only': opt.d = True elif sky_type == 'no-sun': opt.s = True if output_format == 'ASCII': pass elif output_format == 'float': opt.o = 'f' elif output_format == 'double': opt.o = 'd' if not hourly: opt.A = True if not all_hours: opt.u = True if sky_density > 1: opt.m = sky_density cmd = Gendaymtx(wea=wea, options=opt, output=output) if dry_run: print(cmd.to_radiance()) sys.exit(0) try: run_command(cmd.to_radiance(), env=folders.env) except RuntimeError as e: # likely a nighttime Wea; write blank .mtx file with open(output, 'w') as wf: wf.write('') files = [{ 'path': os.path.relpath(output, folder), 'full_path': output }] log_file.write(json.dumps(files)) except Exception: _logger.exception('Failed to generate sunpath.') sys.exit(1) else: sys.exit(0)
def rcontrib_command_with_postprocess( octree, sensor_grid, modifiers, sensor_count, rad_params, rad_params_locked, output, coeff, conversion, output_format, dry_run ): """Run rcontrib command for an input octree and a sensor grid. octree: Path to octree file. sensor-grid: Path to sensor grid file. modifiers: Path to modifiers file. """ try: options = RcontribOptions() # parse input radiance parameters if rad_params: options.update_from_string(rad_params.strip()) # overwrite input values with protected ones if rad_params_locked: options.update_from_string(rad_params_locked.strip()) if not sensor_count: raise ValueError('for time-being sensor count must be provided.') if coeff: options.update_from_string('-aa 0.0 -V- -y {}'.format(sensor_count)) else: options.update_from_string('-aa 0.0 -V+ -y {}'.format(sensor_count)) options.M = modifiers # create command. rcontrib = Rcontrib( options=options, octree=octree, sensors=sensor_grid ) cmd = rcontrib.to_radiance().replace('\\', '/') if conversion and conversion.strip(): # pass the values to rmtxop cmd = '{command} | rmtxop -f{output_format} - -c {conversion}'.format( command=cmd, output_format=output_format, conversion=conversion ) if output: cmd = '{command} > {output}'.format(command=cmd, output=output) if dry_run: click.echo(cmd) else: # rcontrib.run(env=env) run_command(cmd, env=folders.env) except Exception: _logger.exception('Failed to run ray-tracing command.') sys.exit(1) else: sys.exit(0)
def rfluxmtx_command_with_postprocess( octree, sensor_grid, sky_dome, sky_mtx, sensor_count, rad_params, rad_params_locked, output, conversion, output_format, dry_run ): """Run rfluxmtx command and pass the results to rmtxop. octree: Path to octree file. sensor-grid: Path to sensor grid file. sky-dome: Path to sky dome for coefficient calculation. sky-mtx: Path to sky matrix. """ try: options = RfluxmtxOptions() # parse input radiance parameters if rad_params.strip(): options.update_from_string(rad_params.strip()) # overwrite input values with protected ones if rad_params_locked.strip(): options.update_from_string(rad_params_locked.strip()) if not sensor_count: raise ValueError('Number of sensors in senor grid must be provided!') options.update_from_string('-aa 0.0 -faf -y {}'.format(sensor_count)) # create command. cmd_template = 'rfluxmtx {rad_params} - {sky_dome} -i {octree} < ' \ '{sensors} | rmtxop -f{output_format} - {sky_mtx}' if conversion and conversion.strip(): cmd_template = cmd_template + ' -c %s' % conversion if output: cmd_template = cmd_template + ' > {output}'.format(output=output) cmd = cmd_template.format( rad_params=options.to_radiance(), sky_dome=sky_dome, octree=octree, sensors=sensor_grid, output_format=output_format, sky_mtx=sky_mtx ) if dry_run: click.echo(cmd) else: run_command(cmd, env=folders.env) except Exception: _logger.exception('Failed to run rfluxmtx command.') sys.exit(1) else: sys.exit(0)
def three_matrix_operations( first_mtx, second_mtx, third_mtx, operator_one, operator_two, keep_header, conversion, output_mtx, output_format, dry_run ): """Operations between two Radiance matrices. \b Args: first-mtx: Path to fist matrix. second-mtx: Path to second matrix. third-mtx: Path to third matrix. """ try: # first check to be sure there are sun-up hours; if so, write a blank file if os.path.getsize(first_mtx) == 0 or os.path.getsize(second_mtx) == 0 \ or os.path.getsize(third_mtx) == 0: if output_mtx is not None: with open(output_mtx, 'w') as wf: wf.write('') return cmd = 'rmtxop -f{output_format} "{first_mtx}" {operator_one} "{second_mtx}" ' \ ' {operator_two} "{third_mtx}"'.format( output_format=output_format, first_mtx=first_mtx, operator_one=handle_operator(operator_one), second_mtx=second_mtx, operator_two=handle_operator(operator_two), third_mtx=third_mtx ) if conversion and conversion.strip(): cmd = cmd + ' -c {conversion}'.format(conversion=conversion) if not keep_header: cmd = cmd + ' | getinfo - ' if output_mtx: cmd = cmd + ' > "%s"' % output_mtx if dry_run: click.echo(cmd) sys.exit(0) run_command(cmd, env=folders.env) except Exception: _logger.exception('Operation on three Radiance matrix failed.') sys.exit(1) else: sys.exit(0)
def sunpath_from_wea_rad(wea, north, folder, name, visible, log_file, dry_run): """Generate a climate-based sunpath from a Wea file using radiance's gendaymtx. This command also generates a mod file which includes all the modifiers in sunpath. mod file is usually used with rcontrib command to indicate the list of modifiers. Since rcontrib command has a hard limit of 10,000 modifiers in a single run the files will be broken down into multiple files if number of modifiers is more than 10000 modifiers. \b Args: wea: Path to a wea file. """ try: if not os.path.exists(folder): os.makedirs(folder) opt = GendaymtxOptions() opt.n = True opt.D = os.path.join(folder, name + '.mtx').replace('\\', '//') opt.M = os.path.join(folder, name + '.mod').replace('\\', '//') opt.r = north opt.O = '0' if visible else '1' cmd = Gendaymtx(wea=wea, options=opt) if dry_run: print(cmd.to_radiance()) sys.exit(0) run_command(cmd.to_radiance(), env=folders.env) files = [{ 'path': os.path.relpath(path, folder), 'full_path': path } for path in (opt.D.value, opt.M.value)] log_file.write(json.dumps(files)) except Exception: _logger.exception('Failed to generate sunpath.') sys.exit(1) else: sys.exit(0)
def transpose_mtx(input_mtx, output_mtx, dry_run): """Transpose a Radiance matrix. \b Args: input_mtx: Path to input matrix file. """ try: cmd = 'rcollate -t "%s" ' % input_mtx if output_mtx: cmd = cmd + ' > "%s"' % output_mtx if dry_run: click.echo(cmd) sys.exit(0) run_command(cmd, env=folders.env) except Exception: _logger.exception('Matrix transpose command failed.') sys.exit(1) else: sys.exit(0)
def three_phase_rmtxop(view_matrix, t_matrix, daylight_matrix, sky_vector, output_matrix, output_format, illuminance, remove_header, dry_run): """Matrix multiplication for view matrix, transmission matrix, daylight matrix and sky matrix.""" try: options = RmtxopOptions() options.f = output_format matrices = [view_matrix, t_matrix, daylight_matrix, sky_vector] if illuminance: # rmtxop concatenation calc = Rmtxop(matrices=matrices) cmd = Rmtxop(options=options) cmd.transforms = [['47.4', '119.9', '11.6']] cmd.matrices = calc else: cmd = Rmtxop(options=options, matrices=matrices) if remove_header: getinfo = Getinfo.remove_header(output=output_matrix) cmd.pipe_to = getinfo else: cmd.output = output_matrix if dry_run: click.echo(cmd) else: run_command(cmd.to_radiance(), env=folders.env) except OSError: os.system(cmd.to_radiance()) except Exception: _logger.exception( 'Failed to run matrix multiplication calculations with rmtxop') sys.exit(1) else: sys.exit(0)
def rcontrib_command_with_postprocess(octree, sensor_grid, modifiers, sensor_count, rad_params, rad_params_locked, output, coeff, conversion, multiply_by, output_format, order_by_sensor, keep_header, dry_run): """Run rcontrib command for an input octree and a sensor grid. \b Args: octree: Path to octree file. sensor-grid: Path to sensor grid file. modifiers: Path to modifiers file. """ try: # first check to be sure there are sun-up hours; if so, write a blank file if os.path.getsize(modifiers) == 0: if output is not None: with open(output, 'w') as wf: wf.write('') return options = RcontribOptions() # parse input radiance parameters if rad_params: options.update_from_string(rad_params.strip()) # overwrite input values with protected ones if rad_params_locked: options.update_from_string(rad_params_locked.strip()) if not sensor_count: sensor_count = sensor_count_from_file(sensor_grid) if coeff: options.update_from_string( '-aa 0.0 -V- -y {}'.format(sensor_count)) else: options.update_from_string( '-aa 0.0 -V+ -y {}'.format(sensor_count)) options.M = modifiers # create command. rcontrib = Rcontrib(options=options, octree=octree, sensors=sensor_grid) cmd = rcontrib.to_radiance().replace('\\', '/') if conversion and conversion.strip(): if multiply_by != 1: conversion = ' '.join( str(c * multiply_by) for c in conversion.split()) # pass the values to rmtxop cmd = '{command} | rmtxop -f{output_format} - -c {conversion}'.format( command=cmd, output_format=output_format, conversion=conversion) elif multiply_by != 1: conversion = '{mult} {mult} {mult}'.format(mult=multiply_by) cmd = '{command} | rmtxop -f{output_format} - -c {conversion}'.format( command=cmd, output_format=output_format, conversion=conversion) if order_by_sensor is not True: cmd = cmd + ' -t ' if not keep_header: cmd = cmd + ' | getinfo - ' if output: cmd = '{command} > {output}'.format(command=cmd, output=output) if dry_run: click.echo(cmd) else: # rcontrib.run(env=env) run_command(cmd, env=folders.env) except Exception: _logger.exception('Failed to run ray-tracing command.') sys.exit(1) else: sys.exit(0)
def rfluxmtx_command_with_postprocess(octree, sensor_grid, sky_dome, sky_mtx, sensor_count, rad_params, rad_params_locked, output, conversion, multiply_by, output_format, order_by_sensor, keep_header, dry_run): """Run rfluxmtx command and pass the results to rmtxop. octree: Path to octree file. sensor-grid: Path to sensor grid file. sky-dome: Path to sky dome for coefficient calculation. sky-mtx: Path to sky matrix. """ try: # first check to be sure there are sun-up hours; if so, write a blank file if os.path.getsize(sky_mtx) == 0: if output is not None: with open(output, 'w') as wf: wf.write('') return options = RfluxmtxOptions() # parse input radiance parameters if rad_params: options.update_from_string(rad_params.strip()) # overwrite input values with protected ones if rad_params_locked: options.update_from_string(rad_params_locked.strip()) if not sensor_count: sensor_count = sensor_count_from_file(sensor_grid) options.update_from_string('-aa 0.0 -faf -y {}'.format(sensor_count)) # create command. cmd_template = 'rfluxmtx {rad_params} - "{sky_dome}" -i """{octree}""" < ' \ '"{sensors}" | rmtxop -f{output_format} - "{sky_mtx}"' if conversion and conversion.strip(): if multiply_by != 1: conversion = ' '.join( str(c * multiply_by) for c in conversion.split()) cmd_template = cmd_template + ' -c %s' % conversion elif multiply_by != 1: conversion = '{mult} {mult} {mult}'.format(mult=multiply_by) cmd_template = cmd_template + ' -c %s' % conversion if not order_by_sensor: cmd_template = cmd_template + ' -t ' if not keep_header: cmd_template = cmd_template + ' | getinfo - ' if output: cmd_template = cmd_template + ' > "{output}"'.format(output=output) cmd = cmd_template.format(rad_params=options.to_radiance(), sky_dome=sky_dome, octree=octree, sensors=sensor_grid, output_format=output_format, sky_mtx=sky_mtx) if dry_run: click.echo(cmd) else: run_command(cmd, env=folders.env) except Exception: _logger.exception('Failed to run rfluxmtx command.') sys.exit(1) else: sys.exit(0)
def create_view_factor_modifiers(model_file, exclude_sky, exclude_ground, individual_shades, triangulate, folder, name): """Translate a Model into an Octree and corresponding modifier list for view factors. \b Args: model_file: Full path to a Model JSON file (HBJSON) or a Model pkl (HBpkl) file. """ try: # create the directory if it's not there if not os.path.isdir(folder): preparedir(folder) # load the model and ensure the properties align with the energy model model = Model.from_file(model_file) original_units = None if model.units != 'Meters': original_units = model.units model.convert_to_units('Meters') for room in model.rooms: room.remove_colinear_vertices_envelope(tolerance=0.01, delete_degenerate=True) if original_units is not None: model.convert_to_units(original_units) # triangulate the sub-faces if requested if triangulate: apertures, parents_to_edit = model.triangulated_apertures() for tri_aps, edit_infos in zip(apertures, parents_to_edit): if len(edit_infos) == 3: for room in model._rooms: if room.identifier == edit_infos[2]: break for face in room._faces: if face.identifier == edit_infos[1]: break for i, ap in enumerate(face._apertures): if ap.identifier == edit_infos[0]: break face._apertures.pop(i) # remove the aperture to replace face._apertures.extend(tri_aps) doors, parents_to_edit = model.triangulated_doors() for tri_drs, edit_infos in zip(doors, parents_to_edit): if len(edit_infos) == 3: for room in model._rooms: if room.identifier == edit_infos[2]: break for face in room._faces: if face.identifier == edit_infos[1]: break for i, dr in enumerate(face._doors): if dr.identifier == edit_infos[0]: break face._doors.pop(i) # remove the doors to replace face._doors.extend(tri_drs) # set values to be used throughout the modifier assignment offset = model.tolerance * -1 white_plastic = Plastic('white_plastic', 1, 1, 1) geo_strs, mod_strs, mod_names = [], [], [] def _add_geo_and_modifier(hb_obj): """Add a honeybee object to the geometry and modifier strings.""" mod_name = '%s_mod' % hb_obj.identifier mod_names.append(mod_name) white_plastic.identifier = mod_name rad_poly = Polygon(hb_obj.identifier, hb_obj.vertices, white_plastic) geo_strs.append(rad_poly.to_radiance(False, False, False)) mod_strs.append(white_plastic.to_radiance(True, False, False)) # loop through all geometry in the model and get radiance strings for room in model.rooms: for face in room.faces: if not isinstance(face.type, AirBoundary): if isinstance(face.boundary_condition, Surface): face.move(face.normal * offset) _add_geo_and_modifier(face) for ap in face.apertures: _add_geo_and_modifier(ap) for dr in face.doors: _add_geo_and_modifier(dr) all_shades = model.shades + model._orphaned_faces + \ model._orphaned_apertures + model._orphaned_doors if individual_shades: for shade in all_shades: _add_geo_and_modifier(shade) else: white_plastic.identifier = 'shade_plastic_mod' mod_names.append(white_plastic.identifier) mod_strs.append(white_plastic.to_radiance(True, False, False)) for shade in all_shades: rad_poly = Polygon(shade.identifier, shade.vertices, white_plastic) geo_strs.append(rad_poly.to_radiance(False, False, False)) # add the ground and sky domes if requested if not exclude_sky: mod_names.append('sky_glow_mod') mod_strs.append('void glow sky_glow_mod 0 0 4 1 1 1 0') geo_strs.append('sky_glow_mod source sky_dome 0 0 4 0 0 1 180') if not exclude_ground: mod_names.append('ground_glow_mod') mod_strs.append('void glow ground_glow_mod 0 0 4 1 1 1 0') geo_strs.append( 'ground_glow_mod source ground_dome 0 0 4 0 0 -1 180') # write the radiance strings to the output folder geo_file = os.path.join(folder, '{}.rad'.format(name)) mod_file = os.path.join(folder, '{}.mod'.format(name)) oct_file = os.path.join(folder, '{}.oct'.format(name)) with open(geo_file, 'w') as gf: gf.write('\n\n'.join(mod_strs + geo_strs)) with open(mod_file, 'w') as mf: mf.write('\n'.join(mod_names)) # use the radiance files to create an octree cmd = Oconv(output=oct_file, inputs=[geo_file]) cmd.options.f = True run_command(cmd.to_radiance(), env=folders.env) except Exception as e: _logger.exception('Model translation failed.\n{}'.format(e)) sys.exit(1) else: sys.exit(0)
def rcontrib_command_with_view_postprocess(octree, sensor_grid, modifiers, ray_count, rad_params, rad_params_locked, folder, name): """Run rcontrib to get spherical view factors from a sensor grid. \b Args: octree: Path to octree file. sensor-grid: Path to sensor grid file. modifiers: Path to modifiers file. """ try: # create the directory if it's not there if not os.path.isdir(folder): preparedir(folder) # generate the ray vectors to be used in the view factor calculation if ray_count == 6: rays = ((1, 0, 0), (0, 1, 0), (0, 0, 1), (-1, 0, 0), (0, -1, 0), (0, 0, -1)) else: rays = _fibonacci_spiral(ray_count) ray_str = [' {} {} {}\n'.format(*ray) for ray in rays] # create a new .pts file with the view vectors ray_file = os.path.abspath(os.path.join(folder, '{}.pts'.format(name))) total_rays = 0 with open(sensor_grid) as sg_file: with open(ray_file, 'w') as r_file: for line in sg_file: for ray in ray_str: try: r_file.write(' '.join(line.split()[:3]) + ray) total_rays += 1 except Exception: pass # we are at the end of the file # set up the Rcontrib options options = RcontribOptions() if rad_params: # parse input radiance parameters options.update_from_string(rad_params.strip()) if rad_params_locked: # overwrite input values with protected ones options.update_from_string(rad_params_locked.strip()) # overwrite specific options that would otherwise break the command options.M = modifiers options.update_from_string('-I -V- -y {}'.format(total_rays)) # create the rcontrib command and run it mtx_file = os.path.abspath(os.path.join(folder, '{}.mtx'.format(name))) rcontrib = Rcontrib(options=options, octree=octree, sensors=ray_file) cmd = rcontrib.to_radiance().replace('\\', '/') cmd = '{} | rmtxop -fa - -c .333 .333 .334'.format(cmd) cmd = '{} | getinfo - > {}'.format(cmd, mtx_file.replace('\\', '/')) run_command(cmd, env=folders.env) # load the resulting matrix and process the results into view factors view_fac_mtx = [] with open(mtx_file) as mtx_data: while True: sens_lines = list(islice(mtx_data, ray_count)) if not sens_lines: break sens_mtx = ((float(v) for v in ln.strip().split()) for ln in sens_lines) s_facs = [] for sens_facs in zip(*sens_mtx): s_facs.append(sum(sens_facs) / (math.pi * ray_count)) view_fac_mtx.append(s_facs) # write the final view factors into a CSV file view_file = os.path.join(folder, '{}.csv'.format(name)) with open(view_file, 'w') as v_file: for facs in view_fac_mtx: v_file.write(','.join((str(v) for v in facs)) + '\n') except Exception: _logger.exception('Failed to comput view factor contributions.') sys.exit(1) else: sys.exit(0)