class MergeImages(Function): """Merge several .HDR image files with similar starting name into one.""" folder = Inputs.folder( description='Target folder with the input .HDR image files.', path='input_folder') name = Inputs.str(description='Base name for files to be merged.', default='view') extension = Inputs.str( description='File extension including the . before the extension ' '(e.g. .HDR, .pic, .unf)', default='.unf') scale_factor = Inputs.float( description='A number that will be used to scale the dimensions of the ' 'output image as it is filtered for anti-aliasing.', default=1) @command def merge_files(self): return 'honeybee-radiance view merge input_folder view ' \ '{{self.extension}} --scale-factor {{self.scale_factor}} ' \ '--name {{self.name}}' result_image = Outputs.file(description='Output combined image file.', path='{{self.name}}.HDR')
class EnergyUseIntensity(Function): """Get information about energy use intensity from energy simulation SQLite files.""" result_folder = Inputs.folder( description='Path to folder containing SQLite files that were generated ' 'by EnergyPlus. This can be a single EnergyPlus simulation folder or ' 'it can be a folder with multiple sql files, in which case EUI will ' 'be computed across all results.', path='result_folder') units = Inputs.str( description= 'A switch to indicate whether the data in the resulting JSON ' 'should be in SI or IP units. Valid values are "si" and "ip".', default='si', spec={ 'type': 'string', 'enum': ['si', 'ip'] }) @command def energy_use_intensity(self): return 'honeybee-energy result energy-use-intensity result_folder ' \ '--{{inputs.units}} --output-file output.json' eui_json = Outputs.file( description= 'A JSON object with the following keys - eui, total_floor_area, ' 'total_energy, end_uses. The eui value is the energy use intensity across ' 'the total floor area. The end_uses value is a dictionary containing a ' 'breakdown of the eui by end use.', path='output.json')
class CreateOctree(Function): """Generate an octree from a Radiance folder.""" # inputs include_aperture = Inputs.str( default='include', description= 'A value to indicate if the static aperture should be included in ' 'octree. Valid values are include and exclude. Default is include.', spec={ 'type': 'string', 'enum': ['include', 'exclude'] }) black_out = Inputs.str( default='default', description= 'A value to indicate if the black material should be used. Valid ' 'values are default and black. Default value is default.', spec={ 'type': 'string', 'enum': ['black', 'default'] }) model = Inputs.folder(description='Path to Radiance model folder.', path='model') @command def create_octree(self): return 'honeybee-radiance octree from-folder model --output scene.oct ' \ '--{{self.include_aperture}}-aperture --{{self.black_out}}' # outputs scene_file = Outputs.file(description='Output octree file.', path='scene.oct')
class MergeFiles(Function): """Merge several files with similar starting name into one.""" name = Inputs.str( description='Base name for files to be merged.', default='grid' ) extension = Inputs.str( description='File extension including the . before the extension (e.g. .res, ' '.ill)' ) folder = Inputs.folder( description='Target folder with the input files.', path='input_folder' ) @command def merge_files(self): return 'honeybee-radiance grid merge input_folder grid ' \ ' {{self.extension}} --name {{self.name}}' result_file = Outputs.file( description='Output result file.', path='{{self.name}}{{self.extension}}' )
class AnnualDaylightMetrics(Function): """Calculate annual daylight metrics for annual daylight simulation.""" folder = Inputs.folder( description='This folder is an output folder of annual daylight recipe. Folder ' 'should include grids_info.json and sun-up-hours.txt. The command uses the list ' 'in grids_info.json to find the result files for each sensor grid.', path='raw_results' ) schedule = Inputs.file( description='Path to an annual schedule file. Values should be 0-1 separated ' 'by new line. If not provided an 8-5 annual schedule will be created.', path='schedule.txt', optional=True ) thresholds = Inputs.str( description='A string to change the threshold for daylight autonomy and useful ' 'daylight illuminance. Valid keys are -t for daylight autonomy threshold, -lt ' 'for the lower threshold for useful daylight illuminance and -ut for the upper ' 'threshold. The defult is -t 300 -lt 100 -ut 3000. The order of the keys is not ' 'important and you can include one or all of them. For instance if you only ' 'want to change the upper threshold to 2000 lux you should use -ut 2000 as ' 'the input.', default='-t 300 -lt 100 -ut 3000' ) @command def calculate_annual_metrics(self): return 'honeybee-radiance post-process annual-daylight raw_results ' \ '--schedule schedule.txt {{self.thresholds}} --sub_folder ../metrics' # outputs annual_metrics = Outputs.folder( description='Annual metrics folder. This folder includes all the other ' 'subfolders which are also exposed as separate outputs.', path='metrics' ) daylight_autonomy = Outputs.folder( description='Daylight autonomy results.', path='metrics/da' ) continuous_daylight_autonomy = Outputs.folder( description='Continuous daylight autonomy results.', path='metrics/cda' ) useful_daylight_illuminance_lower = Outputs.folder( description='Lower useful daylight illuminance results.', path='metrics/udi_lower' ) useful_daylight_illuminance = Outputs.folder( description='Useful daylight illuminance results.', path='metrics/udi' ) useful_daylight_illuminance_upper = Outputs.folder( description='Upper useful daylight illuminance results.', path='metrics/udi_upper' )
class RayTracingPicture(Function): """Run ray-tracing with rpict command for an input octree and a view file..""" view = Inputs.file(description='Input view file.', path='view.vf') scene_file = Inputs.file( description='Path to an octree file to describe the scene.', path='scene.oct' ) radiance_parameters = Inputs.str( description='Radiance parameters to be exposed within recipes. -h is ' 'usually already included in the fixed_radiance_parameters and -I will ' 'be overwritten based on the input metric.', default='-ab 2' ) metric = Inputs.str( description='Text for the type of metric to be output from the calculation. ' 'Choose from: illuminance, irradiance, luminance, radiance.', default='luminance', spec={'type': 'string', 'enum': ['illuminance', 'irradiance', 'luminance', 'radiance']} ) resolution = Inputs.int( description='An integer for the maximum dimension of the image in pixels ' '(either width or height depending on the input view angle and type).', spec={'type': 'integer', 'minimum': 1}, default=512 ) scale_factor = Inputs.float( description='A number that will be multiplied by the input resolution to ' 'scale the dimensions of the output image. This is useful in workflows if ' 'one plans to re-scale the image after the ray tracing calculation to ' 'improve anti-aliasing.', default=1 ) ambient_cache = Inputs.file( description='Path to the ambient cache if an overture calculation was ' 'specified. If unspecified, no ambient cache will be used.', path='view.amb', optional=True ) bsdf_folder = Inputs.folder( description='Folder containing any BSDF files needed for ray tracing.', path='model/bsdf', optional=True ) @command def ray_tracing(self): return 'honeybee-radiance rpict rpict scene.oct view.vf ' \ '--rad-params "{{self.radiance_parameters}}" --metric {{self.metric}} ' \ '--resolution {{self.resolution}} --scale-factor {{self.scale_factor}} ' \ '--output view.HDR' result_image = Outputs.file( description='Path to the High Dynamic Range (HDR) image file of the ' 'input view.', path='view.HDR' )
class RayTracingPointInTime(Function): """Run ray-tracing and post-process the results for a point-in-time simulation.""" radiance_parameters = Inputs.str( description='Radiance parameters to be exposed within recipes. -h is ' 'usually already included in the fixed_radiance_parameters and -I will ' 'be overwritten based on the input metric.', default='-ab 2') metric = Inputs.str( description= 'Text for the type of metric to be output from the calculation. ' 'Choose from: illuminance, irradiance, luminance, radiance.', default='illuminance', spec={ 'type': 'string', 'enum': ['illuminance', 'irradiance', 'luminance', 'radiance'] }) fixed_radiance_parameters = Inputs.str( description= 'Parameters that are meant to be fixed for a given recipe and ' 'should not be overwritten by radiance_parameters input.', default='-h') grid = Inputs.file(description='Input sensor grid.', path='grid.pts') scene_file = Inputs.file( description='Path to an octree file to describe the scene.', path='scene.oct') bsdf_folder = Inputs.folder( description='Folder containing any BSDF files needed for ray tracing.', path='model/bsdf', optional=True) @command def ray_tracing(self): return 'honeybee-radiance raytrace point-in-time scene.oct grid.pts ' \ '--rad-params "{{self.radiance_parameters}}" --rad-params-locked ' \ '"{{self.fixed_radiance_parameters}}" --metric {{self.metric}} ' \ '--output grid.res' result = Outputs.file( description= 'Point-in-time result file. The result for each sensor is in a ' 'new line of the file. Values are in standard SI units of the input ' 'metric (lux, W/m2, cd/m2, W/m2-sr).', path='grid.res')
class SplitGridFromFolder(SplitGrid): """Split a single sensor grid file into multiple grids based on maximum number of sensors. This function takes a folder of sensor grids and find the target grid based on grid-name. """ name = Inputs.str(description='Grid name.') input_grid = Inputs.folder(description='Path to sensor grids folder.', path='.') @command def split_grid(self): return 'honeybee-radiance grid split {{self.name}}.pts ' \ '{{self.sensor_count}} --folder output --log-file output/grids_info.json'
class AnnualIrradianceMetrics(Function): """Calculate annual irradiance metrics for annual irradiance simulation.""" folder = Inputs.folder( description='A folder output from and annual irradiance recipe.', path='raw_results') wea = Inputs.file( description= 'The .wea file that was used in the annual irradiance simulation. ' 'This will be used to determine the duration of the analysis for computing ' 'average irradiance.', path='weather.wea') timestep = Inputs.int( description='The timestep of the Wea file, which is used to ensure the ' 'summed row of irradiance yields cumulative radiation over the time ' 'period of the Wea.', default=1) @command def calculate_irradiance_metrics(self): return 'honeybee-radiance post-process annual-irradiance raw_results ' \ 'weather.wea --timestep {{self.timestep}} --sub-folder ../metrics' # outputs metrics = Outputs.folder( description='Annual irradiance metrics folder. This folder includes all ' 'the other subfolders which are exposed as separate outputs.', path='metrics') average_irradiance = Outputs.folder( description= 'Average irradiance in W/m2 for each sensor over the wea period.', path='metrics/average_irradiance') peak_irradiance = Outputs.folder( description= 'The highest irradiance value in W/m2 for each sensor during ' 'the wea period.', path='metrics/average_irradiance') cumulative_radiation = Outputs.folder( description='The cumulative radiation in kWh/m2 for each sensor over ' 'the wea period.', path='metrics/cumulative_radiation')
class LeedIlluminanceCredits(Function): """Estimate LEED daylight credits from two point-in-time illuminance folders.""" folder = Inputs.folder( description= 'Project folder for a LEED illuminance simulation. It should ' 'contain a HBJSON model and two sub-folders of complete point-in-time ' 'illuminance simulations labeled "9AM" and "3PM". These two sub-folders should ' 'each have results folders that include a grids_info.json and .res files with ' 'illuminance values for each sensor. If Meshes are found for the sensor ' 'grids in the HBJSON file, they will be used to compute percentages ' 'of occupied floor area that pass vs. fail. Otherwise, all sensors will ' 'be assumed to represent an equal amount of floor area.', path='raw_results') glare_control_devices = Inputs.str( description= 'A switch to note whether the model has "view-preserving automatic ' '(with manual override) glare-control devices," which means that illuminance ' 'only needs to be above 300 lux and not between 300 and 3000 lux.', default='glare-control', spec={ 'type': 'string', 'enum': ['glare-control', 'no-glare-control'] }) @command def calculate_leed_credits(self): return 'honeybee-radiance post-process leed-illuminance raw_results ' \ '--{{self.glare_control_devices}} --sub-folder ../pass_fail ' \ '--output-file credit_summary.json' # outputs pass_fail_results = Outputs.folder( description='Pass/Fail results folder. This folder includes results for ' 'each sensor indicating whether they pass or fail the LEED criteria.', path='pass_fail') credit_summary = Outputs.folder( description= 'JSON file containing the number of LEED credits achieved and ' 'a summary of the percentage of the sensor grid area that meets the criteria.', path='credit_summary.json')
class RayTracingDaylightFactor(Function): """Run ray-tracing and post-process the results for a daylight factor simulation.""" radiance_parameters = Inputs.str( description= 'Radiance parameters to be exposed within recipes. -I and -h are ' 'usually already included in the fixed_radiance_parameters.', default='-ab 2') sky_illum = Inputs.int( description='Sky illuminance level for the sky included in octree.', default=100000) fixed_radiance_parameters = Inputs.str( description= 'Parameters that are meant to be fixed for a given recipe and ' 'should not be overwritten by radiance_parameters input.', default='-I -h') grid = Inputs.file(description='Input sensor grid.', path='grid.pts') scene_file = Inputs.file( description='Path to an octree file to describe the scene.', path='scene.oct') bsdf_folder = Inputs.folder( description='Folder containing any BSDF files needed for ray tracing.', path='model/bsdf', optional=True) @command def ray_tracing(self): return 'honeybee-radiance raytrace daylight-factor scene.oct grid.pts ' \ '--rad-params "{{self.radiance_parameters}}" --rad-params-locked ' \ '"{{self.fixed_radiance_parameters}}" --sky-illum {{self.sky_illum}} ' \ '--output grid.res' result = Outputs.file( description= 'Daylight factor results file. The results for each sensor is in a ' 'new line.', path='grid.res')
class DaylightCoefficient(Function): """Calculate daylight coefficient for a grid of sensors from a sky matrix.""" radiance_parameters = Inputs.str( description= 'Radiance parameters. -I, -c 1 and -aa 0 are already included in ' 'the command.', default='') fixed_radiance_parameters = Inputs.str( description= 'Radiance parameters. -I, -c 1 and -aa 0 are already included in ' 'the command.', default='-aa 0') sensor_count = Inputs.int( description='Number of maximum sensors in each generated grid.', spec={ 'type': 'integer', 'minimum': 1 }) sky_matrix = Inputs.file(description='Path to a sky matrix.', path='sky.mtx', extensions=['mtx', 'smx']) sky_dome = Inputs.file(description='Path to a sky dome.', path='sky.dome') sensor_grid = Inputs.file(description='Path to sensor grid files.', path='grid.pts', extensions=['pts']) scene_file = Inputs.file( description='Path to an octree file to describe the scene.', path='scene.oct', extensions=['oct']) conversion = Inputs.str( description= 'Conversion values as a string which will be passed to rmtxop -c.' 'This option is useful to post-process the results from 3 RGB components into ' 'one as part of this command.', default='') order_by = Inputs.str( description= 'An option to change how results are ordered in each row. By ' 'default each row are the results for each sensor during all the datetime. ' 'Valid options are sensor and datetime.', default='sensor', spec={ 'type': 'string', 'enum': ['sensor', 'datetime'] }) output_format = Inputs.str( description= 'Output format for converted results. Valid inputs are a, f and ' 'd for ASCII, float or double.', default='f', spec={ 'type': 'string', 'enum': ['a', 'd', 'f'] }) bsdf_folder = Inputs.folder( description='Folder containing any BSDF files needed for ray tracing.', path='model/bsdf', optional=True) @command def run_daylight_coeff(self): return 'honeybee-radiance dc scoeff scene.oct grid.pts sky.dome sky.mtx ' \ '--sensor-count {{self.sensor_count}} --output results.ill --rad-params ' \ '"{{self.radiance_parameters}}" --rad-params-locked '\ '"{{self.fixed_radiance_parameters}}" --conversion "{{self.conversion}}" ' \ '--output-format {{self.output_format}} --order-by-{{self.order_by}}' result_file = Outputs.file(description='Output result file.', path='results.ill')
class DaylightContribution(Function): """ Calculate daylight contribution for a grid of sensors from a series of modifiers using rcontrib command. """ radiance_parameters = Inputs.str( description='Radiance parameters. -I and -aa 0 are already included in ' 'the command.', default='' ) fixed_radiance_parameters = Inputs.str( description='Radiance parameters. -I and -aa 0 are already included in ' 'the command.', default='-aa 0' ) calculate_values = Inputs.str( description='A switch to indicate if the values should be multiplied. ' 'Otherwise the contribution is calculated as a coefficient. Default is set to ' 'value. Use coeff for contribution', default='value', spec={'type': 'string', 'enum': ['value', 'coeff']} ) conversion = Inputs.str( description='Conversion values as a string which will be passed to rmtxop -c.', default='' ) order_by = Inputs.str( description='An option to change how results are grouped in each row. By ' 'default each row are the results for each sensor during all the datetimes. ' 'Valid options are sensor and datetime.', default='sensor', spec={'type': 'string', 'enum': ['sensor', 'datetime']} ) output_format = Inputs.str( description='Output format for converted results. Valid inputs are a, f and ' 'd for ASCII, float or double. If conversion is not provided you can change the ' 'output format using rad-params options.', default='a', spec={'type': 'string', 'enum': ['a', 'd', 'f']} ) sensor_count = Inputs.int( description='Number of maximum sensors in each generated grid.', spec={'type': 'integer', 'minimum': 1} ) modifiers = Inputs.file( description='Path to modifiers file. In most cases modifiers are sun modifiers.', path='suns.mod' ) sensor_grid = Inputs.file( description='Path to sensor grid files.', path='grid.pts', extensions=['pts'] ) scene_file = Inputs.file( description='Path to an octree file to describe the scene.', path='scene.oct', extensions=['oct'] ) bsdf_folder = Inputs.folder( description='Folder containing any BSDF files needed for ray tracing.', path='model/bsdf', optional=True ) @command def run_daylight_coeff(self): return 'honeybee-radiance dc scontrib scene.oct grid.pts suns.mod ' \ '--{{self.calculate_values}} --sensor-count {{self.sensor_count}} ' \ '--rad-params "{{self.radiance_parameters}}" --rad-params-locked ' \ '"{{self.fixed_radiance_parameters}}" --conversion "{{self.conversion}}" ' \ '--output-format {{self.output_format}} --output results.ill ' \ '--order-by-{{self.order_by}}' result_file = Outputs.file(description='Output result file.', path='results.ill')
class SplitView(Function): """Split a single view file (.vf) into multiple smaller views.""" view_count = Inputs.int( description= 'Number of views into which the input view will be subdivided.', spec={ 'type': 'integer', 'minimum': 1 }) input_view = Inputs.file(description='Input view file.', path='view.vf') overture = Inputs.str( description='A switch to note whether an ambient file (.amb) should be ' 'generated for an overture calculation before the view is split into smaller ' 'views. With an overture calculation, the ambient file (aka ambient cache) is ' 'first populated with values. Thereby ensuring that - when reused to create ' 'an image - Radiance uses interpolation between already calculated values ' 'rather than less reliable extrapolation. The overture calculation has ' 'comparatively small computation time to full rendering but is single-core ' 'can become time consuming in situations with very high numbers of ' 'rendering multiprocessors.', default='overture', spec={ 'type': 'string', 'enum': ['overture', 'skip-overture'] }) scene_file = Inputs.file( description= 'Path to an octree file for the overture calculation. This must be ' 'specified when the overture is not skipped.', path='scene.oct', optional=True) radiance_parameters = Inputs.str( description='Radiance parameters for the overture calculation. ' 'If unspecified, default rpict paramters will be used.', default='-ab 2') bsdf_folder = Inputs.folder( description='Folder containing any BSDF files needed for ray tracing.', path='model/bsdf', optional=True) @command def split_view(self): return 'honeybee-radiance view split view.vf ' \ '{{self.view_count}} --{{self.overture}} ' \ '--octree {{self.scene_file}} --rad-params "{{self.radiance_parameters}}" ' \ '--folder output --log-file output/views_info.json' views_list = Outputs.list( description='A JSON array that includes information about generated ' 'views.', path='output/views_info.json') output_folder = Outputs.folder( description='Output folder with new view files.', path='output') ambient_cache = Outputs.file( description='Path to the ambient cache if an overture calculation was ' 'specified.', path='output/view.amb', optional=True)
class ShortwaveMrtMap(Function): """Get CSV files with maps of shortwave MRT Deltas from Radiance results.""" epw = Inputs.file( description='Weather file used to compute sun positions.', path='weather.epw', extensions=['epw']) indirect_irradiance = Inputs.file( description= 'A Radiance .ill containing the indirect irradiance for each ' 'sensor. Alternatively, if the indirect-is-total input is used, then this ' 'input should be the total irradiance for each sensor.', path='indirect.ill', extensions=['ill', 'irr']) direct_irradiance = Inputs.file( description= 'A Radiance .ill containing direct irradiance for each sensor.', path='direct.ill', extensions=['ill', 'irr']) ref_irradiance = Inputs.file( description= 'A Radiance .ill containing ground-reflected irradiance for each ' 'sensor.', path='ref.ill', extensions=['ill', 'irr']) sun_up_hours = Inputs.file( description= 'A sun-up-hours.txt file output by Radiance and aligns with the ' 'input irradiance files.', path='sun-up-hours.txt') contributions = Inputs.folder( description='An optional folder containing sub-folders of irradiance ' 'contributions from dynamic aperture groups. There should be one sub-folder ' 'per window groups and each one should contain three .ill files named ' 'direct.ill, indirect.ill and reflected.ill. If specified, these will be ' 'added to the irradiance inputs before computing shortwave MRT deltas.', path='dynamic', optional=True) transmittance_contribs = Inputs.folder( description= 'An optional folder containing a transmittance schedule JSON ' 'and sub-folders of irradiance results that exclude the shade from the ' 'calculation. There should be one sub-folder per window groups and each ' 'one should contain three .ill files named direct.ill, indirect.ill and ' 'reflected.ill. If specified, these will be added to the irradiance inputs ' 'before computing shortwave MRT deltas.', path='dyn_shade', optional=True) trans_schedules = Inputs.file( description= 'An optional path to a transmittance schedule JSON output by ' 'the honeybee-energy model-transmittance-schedules command, which is ' 'coordinated with the --transmittance-contribs.', path='trans_schedules.json', optional=True) solarcal_par = Inputs.str( description='A SolarCalParameter string to customize the assumptions of ' 'the SolarCal model.', default='--posture seated --sharp 135 ' '--absorptivity 0.7 --emissivity 0.95') run_period = Inputs.str( description= 'An AnalysisPeriod string to set the start and end dates of the ' 'analysis (eg. "6/21 to 9/21 between 8 and 16 @1"). If unspecified, results ' 'will be annual.', default='') indirect_is_total = Inputs.str( description= 'A switch to note whether the indirect-irradiance argument is ' 'actually the total irradiance.', default='is-indirect', spec={ 'type': 'string', 'enum': ['is-indirect', 'indirect-is-total'] }) @command def run_shortwave_map(self): return 'ladybug-comfort map shortwave-mrt weather.epw indirect.ill direct.ill ' \ 'ref.ill sun-up-hours.txt --contributions dynamic ' \ '--transmittance-contribs dyn_shade --trans-schedule-json ' \ 'trans_schedules.json --solarcal-par "{{self.solarcal_par}}" ' \ '--run-period "{{self.run_period}}" --{{self.indirect_is_total}} ' \ '--output-file shortwave.csv' shortwave_mrt_map = Outputs.file( description='CSV file containing a map of shortwave MRT deltas.', path='shortwave.csv')