예제 #1
0
class DirectSunHoursEntryLoop(DAG):
    # inputs
    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution',
        spec={
            'type': 'integer',
            'minimum': 1
        })

    octree_file = Inputs.file(description='A Radiance octree file with suns.',
                              extensions=['oct'])

    grid_name = Inputs.str(
        description=
        'Sensor grid file name. This is useful to rename the final result '
        'file to {grid_name}.ill')

    sensor_grid = Inputs.file(description='Sensor grid file.',
                              extensions=['pts'])

    sun_modifiers = Inputs.file(description='A file with sun modifiers.')

    @task(template=SplitGrid)
    def split_grid(self, sensor_count=sensor_count, input_grid=sensor_grid):
        return [{
            'from': SplitGrid()._outputs.grids_list
        }, {
            'from': SplitGrid()._outputs.output_folder,
            'to': 'sub_grids'
        }]

    @task(template=DirectSunHoursCalculation,
          needs=[split_grid],
          loop=split_grid._outputs.grids_list,
          sub_paths={'sensor_grid': '{{item.path}}'})
    def direct_sunlight(self,
                        octree_file=octree_file,
                        sensor_count='{{item.count}}',
                        grid_name='{{item.name}}',
                        sun_modifiers=sun_modifiers,
                        sensor_grid=split_grid._outputs.output_folder,
                        scene_file=octree_file):
        # the results of the loop will be collected under direct_sunlight subfolder.
        pass

    @task(template=MergeFiles, needs=[direct_sunlight])
    def merge_direct_sun_hours(self,
                               name=grid_name,
                               extension='.ill',
                               folder='direct-sun-hours'):
        """Merge direct sun hour results from several grids into a single file."""
        return [{
            'from': MergeFiles()._outputs.result_file,
            'to': '../../results/direct_sun_hours/{{self.name}}.ill'
        }]

    @task(template=MergeFiles, needs=[direct_sunlight])
    def merge_cumulative_sun_hours(self,
                                   name=grid_name,
                                   extension='.res',
                                   folder='cumulative-sun-hours'):
        """Merge cumulative sun hour results from several grids into a single file."""
        return [{
            'from': MergeFiles()._outputs.result_file,
            'to': '../../results/cumulative/{{self.name}}.res'
        }]
예제 #2
0
class AnnualSkyRadiationEntryPoint(DAG):
    """Annual Sky Radiation entry point."""

    # inputs
    north = Inputs.float(default=0,
                         description='A number for rotation from north.',
                         spec={
                             'type': 'number',
                             'minimum': -360,
                             'maximum': 360
                         },
                         alias=north_input)

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution.',
        spec={
            'type': 'integer',
            'minimum': 1
        })

    radiance_parameters = Inputs.str(
        description='Radiance parameters for ray tracing.', default='-ab 1')

    sensor_grid = Inputs.str(
        description=
        'A grid name or a pattern to filter the sensor grids. By default '
        'all the grids in HBJSON model will be exported.',
        default='*')

    sky_density = Inputs.int(
        default=1,
        description=
        'The density of generated sky. This input corresponds to gendaymtx '
        '-m option. -m 1 generates 146 patch starting with 0 for the ground and '
        'continuing to 145 for the zenith. Increasing the -m parameter yields a higher '
        'resolution sky using the Reinhart patch subdivision. For example, setting -m 4 '
        'yields a sky with 2305 patches plus one patch for the ground.',
        spec={
            'type': 'integer',
            'minimum': 1
        })

    cumulative = Inputs.str(
        description=
        'An option to generate a cumulative sky instead of an hourly sky',
        default='hourly',
        spec={
            'type': 'string',
            'enum': ['hourly', 'cumulative']
        })

    order_by = Inputs.str(
        description=
        'Order of the output results. By default the results are ordered '
        'to include the results for a single sensor in each row.',
        default='sensor',
        spec={
            'type': 'string',
            'enum': ['sensor', 'datetime']
        })

    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'],
                        alias=hbjson_model_input)

    wea = Inputs.file(description='Wea file.',
                      extensions=['wea'],
                      alias=wea_input)

    timestep = Inputs.int(
        description='Input wea timestep. This value will be used to divide the '
        'cumulative results.',
        default=1,
        spec={
            'type': 'integer',
            'minimum': 1,
            'maximum': 60
        })

    leap_year = Inputs.str(
        description=
        'A flag to indicate if datetimes in the wea file are for a leap '
        'year.',
        default='full-year',
        spec={
            'type': 'string',
            'enum': ['full-year', 'leap-year']
        })

    black_out = Inputs.str(
        default='default',
        description=
        'A value to indicate if the black material should be used for . '
        'the calculation. Valid values are default and black. Default value is default.',
        spec={
            'type': 'string',
            'enum': ['black', 'default']
        })

    @task(template=CreateSunMatrix)
    def generate_sunpath(self, north=north, wea=wea, output_type=1):
        """Create sunpath for sun-up-hours.

        The sunpath is not used to calculate radiation values.
        """
        return [{
            'from': CreateSunMatrix()._outputs.sunpath,
            'to': 'resources/sunpath.mtx'
        }, {
            'from': CreateSunMatrix()._outputs.sun_modifiers,
            'to': 'resources/suns.mod'
        }]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(
            self,
            sun_modifiers=generate_sunpath._outputs.sun_modifiers,
            leap_year=leap_year,
            timestep=timestep):
        return [{
            'from': ParseSunUpHours()._outputs.sun_up_hours,
            'to': 'results/sun-up-hours.txt'
        }]

    @task(template=CreateRadianceFolder)
    def create_rad_folder(self, input_model=model, sensor_grid=sensor_grid):
        """Translate the input model to a radiance folder."""
        return [{
            'from': CreateRadianceFolder()._outputs.model_folder,
            'to': 'model'
        }, {
            'from': CreateRadianceFolder()._outputs.sensor_grids_file,
            'to': 'results/grids_info.json'
        }, {
            'from': CreateRadianceFolder()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(template=CreateOctree, needs=[create_rad_folder])
    def create_octree(self,
                      model=create_rad_folder._outputs.model_folder,
                      black_out=black_out):
        """Create octree from radiance folder."""
        return [{
            'from': CreateOctree()._outputs.scene_file,
            'to': 'resources/scene.oct'
        }]

    @task(template=CreateSkyDome)
    def create_sky_dome(self, sky_density=sky_density):
        """Create sky dome for daylight coefficient studies."""
        return [{
            'from': CreateSkyDome()._outputs.sky_dome,
            'to': 'resources/sky.dome'
        }]

    @task(template=CreateSkyMatrix)
    def create_sky(self,
                   north=north,
                   wea=wea,
                   sky_type='total',
                   output_type='solar',
                   output_format='ASCII',
                   sky_density=sky_density,
                   cumulative=cumulative,
                   sun_up_hours='sun-up-hours'):
        return [{
            'from': CreateSkyMatrix()._outputs.sky_matrix,
            'to': 'resources/sky.mtx'
        }]

    @task(
        template=AnnualSkyRadiationRayTracing,
        needs=[create_sky_dome, create_octree, create_sky, create_rad_folder],
        loop=create_rad_folder._outputs.sensor_grids,
        sub_folder=
        'initial_results/{{item.name}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid': 'grid/{{item.full_id}}.pts'})
    def annual_sky_radiation_raytracing(
            self,
            sensor_count=sensor_count,
            radiance_parameters=radiance_parameters,
            octree_file=create_octree._outputs.scene_file,
            grid_name='{{item.full_id}}',
            sensor_grid=create_rad_folder._outputs.model_folder,
            sky_dome=create_sky_dome._outputs.sky_dome,
            sky_matrix=create_sky._outputs.sky_matrix,
            order_by=order_by):
        pass

    results = Outputs.folder(description='Total radiation results.',
                             source='results',
                             alias=annual_daylight_results)
예제 #3
0
class DaylightFactorEntryPoint(DAG):
    """Daylight factor entry point."""

    # inputs
    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'],
                        alias=hbjson_model_grid_input)

    cpu_count = Inputs.int(
        default=50,
        description=
        'The maximum number of CPUs for parallel execution. This will be '
        'used to determine the number of sensors run by each worker.',
        spec={
            'type': 'integer',
            'minimum': 1
        },
        alias=cpu_count)

    min_sensor_count = Inputs.int(
        description='The minimum number of sensors in each sensor grid after '
        'redistributing the sensors based on cpu_count. This value takes '
        'precedence over the cpu_count and can be used to ensure that '
        'the parallelization does not result in generating unnecessarily small '
        'sensor grids. The default value is set to 1, which means that the '
        'cpu_count is always respected.',
        default=1,
        spec={
            'type': 'integer',
            'minimum': 1
        },
        alias=min_sensor_count_input)

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing',
        default='-ab 2 -aa 0.1 -ad 2048 -ar 64',
        alias=rad_par_daylight_factor_input)

    grid_filter = Inputs.str(
        description=
        'Text for a grid identifier or a pattern to filter the sensor grids '
        'of the model that are simulated. For instance, first_floor_* will simulate '
        'only the sensor grids that have an identifier that starts with '
        'first_floor_. By default, all grids in the model will be simulated.',
        default='*',
        alias=grid_filter_input)

    @task(template=GenSkyWithCertainIllum)
    def generate_sky(self):
        return [{
            'from': GenSkyWithCertainIllum()._outputs.sky,
            'to': 'resources/100000_lux.sky'
        }]

    @task(template=CreateRadianceFolderGrid)
    def create_rad_folder(self, input_model=model, grid_filter=grid_filter):
        """Translate the input model to a radiance folder."""
        return [{
            'from': CreateRadianceFolderGrid()._outputs.model_folder,
            'to': 'model'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.bsdf_folder,
            'to': 'model/bsdf'
        }, {
            'from':
            CreateRadianceFolderGrid()._outputs.model_sensor_grids_file,
            'to': 'results/daylight-factor/grids_info.json'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(template=CreateOctreeWithSky,
          needs=[generate_sky, create_rad_folder])
    def create_octree(self,
                      model=create_rad_folder._outputs.model_folder,
                      sky=generate_sky._outputs.sky):
        """Create octree from radiance folder and sky."""
        return [{
            'from': CreateOctreeWithSky()._outputs.scene_file,
            'to': 'resources/scene.oct'
        }]

    @task(template=SplitGridFolder,
          needs=[create_rad_folder],
          sub_paths={'input_folder': 'grid'})
    def split_grid_folder(self,
                          input_folder=create_rad_folder._outputs.model_folder,
                          cpu_count=cpu_count,
                          cpus_per_grid=1,
                          min_sensor_count=min_sensor_count):
        """Split sensor grid folder based on the number of CPUs"""
        return [{
            'from': SplitGridFolder()._outputs.output_folder,
            'to': 'resources/grid'
        }, {
            'from': SplitGridFolder()._outputs.dist_info,
            'to': 'initial_results/_redist_info.json'
        }, {
            'from': SplitGridFolder()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(
        template=RayTracingDaylightFactor,
        needs=[create_rad_folder, split_grid_folder, create_octree],
        loop=split_grid_folder._outputs.sensor_grids,
        sub_folder='initial_results/{{item.full_id}}',  # subfolder for each grid
        sub_paths={'grid': '{{item.full_id}}.pts'}  # sensor_grid sub_path
    )
    def daylight_factor_ray_tracing(
            self,
            radiance_parameters=radiance_parameters,
            scene_file=create_octree._outputs.scene_file,
            grid=split_grid_folder._outputs.output_folder,
            bsdf_folder=create_rad_folder._outputs.bsdf_folder):
        return [{
            'from': RayTracingDaylightFactor()._outputs.result,
            'to': '../{{item.name}}.res'
        }]

    @task(template=MergeFolderData, needs=[daylight_factor_ray_tracing])
    def restructure_results(self,
                            input_folder='initial_results',
                            extension='res'):
        return [{
            'from': MergeFolderData()._outputs.output_folder,
            'to': 'results/daylight-factor'
        }]

    results = Outputs.folder(
        source='results/daylight-factor',
        description='Folder with raw result files '
        '(.res) that contain daylight factor values for each sensor.',
        alias=daylight_factor_results)
예제 #4
0
class AnnualDaylightEntryPoint(DAG):
    """Annual daylight entry point."""

    # inputs
    north = Inputs.float(default=0,
                         description='A number for rotation from north.',
                         spec={
                             'type': 'number',
                             'minimum': 0,
                             'maximum': 360
                         },
                         alias=north_input)

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution.',
        spec={
            'type': 'integer',
            'minimum': 1
        },
        alias=sensor_count_input)

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05',
        alias=rad_par_annual_input)

    grid_filter = Inputs.str(
        description=
        'Text for a grid identifer or a pattern to filter the sensor grids '
        'of the model that are simulated. For instance, first_floor_* will simulate '
        'only the sensor grids that have an identifier that starts with '
        'first_floor_. By default, all grids in the model will be simulated.',
        default='*',
        alias=grid_filter_input)

    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'],
                        alias=hbjson_model_input)

    wea = Inputs.file(description='Wea file.',
                      extensions=['wea'],
                      alias=wea_input)

    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.',
        extensions=['txt', 'csv'],
        optional=True,
        alias=schedule_csv_input)

    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 default 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',
        alias=daylight_thresholds_input)

    @task(template=CreateSunMatrix)
    def generate_sunpath(self, north=north, wea=wea):
        """Create sunpath for sun-up-hours."""
        return [{
            'from': CreateSunMatrix()._outputs.sunpath,
            'to': 'resources/sunpath.mtx'
        }, {
            'from': CreateSunMatrix()._outputs.sun_modifiers,
            'to': 'resources/suns.mod'
        }]

    @task(template=CreateRadianceFolderGrid)
    def create_rad_folder(self, input_model=model, grid_filter=grid_filter):
        """Translate the input model to a radiance folder."""
        return [{
            'from': CreateRadianceFolderGrid()._outputs.model_folder,
            'to': 'model'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids_file,
            'to': 'results/grids_info.json'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(template=CreateOctree, needs=[create_rad_folder])
    def create_octree(self, model=create_rad_folder._outputs.model_folder):
        """Create octree from radiance folder."""
        return [{
            'from': CreateOctreeWithSky()._outputs.scene_file,
            'to': 'resources/scene.oct'
        }]

    @task(template=CreateOctreeWithSky,
          needs=[generate_sunpath, create_rad_folder])
    def create_octree_with_suns(self,
                                model=create_rad_folder._outputs.model_folder,
                                sky=generate_sunpath._outputs.sunpath):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [{
            'from': CreateOctreeWithSky()._outputs.scene_file,
            'to': 'resources/scene_with_suns.oct'
        }]

    @task(template=CreateSkyDome)
    def create_sky_dome(self):
        """Create sky dome for daylight coefficient studies."""
        return [{
            'from': CreateSkyDome()._outputs.sky_dome,
            'to': 'resources/sky.dome'
        }]

    @task(template=CreateSkyMatrix)
    def create_total_sky(self,
                         north=north,
                         wea=wea,
                         sun_up_hours='sun-up-hours'):
        return [{
            'from': CreateSkyMatrix()._outputs.sky_matrix,
            'to': 'resources/sky.mtx'
        }]

    @task(template=CreateSkyMatrix)
    def create_direct_sky(self,
                          north=north,
                          wea=wea,
                          sky_type='sun-only',
                          sun_up_hours='sun-up-hours'):
        return [{
            'from': CreateSkyMatrix()._outputs.sky_matrix,
            'to': 'resources/sky_direct.mtx'
        }]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(
            self, sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        return [{
            'from': ParseSunUpHours()._outputs.sun_up_hours,
            'to': 'results/sun-up-hours.txt'
        }]

    @task(
        template=AnnualDaylightRayTracing,
        needs=[
            create_sky_dome, create_octree_with_suns, create_octree,
            generate_sunpath, create_total_sky, create_direct_sky,
            create_rad_folder
        ],
        loop=create_rad_folder._outputs.sensor_grids,
        sub_folder=
        'initial_results/{{item.name}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid':
                   'grid/{{item.full_id}}.pts'}  # sub_path for sensor_grid arg
    )
    def annual_daylight_raytracing(
            self,
            sensor_count=sensor_count,
            radiance_parameters=radiance_parameters,
            octree_file_with_suns=create_octree_with_suns._outputs.scene_file,
            octree_file=create_octree._outputs.scene_file,
            grid_name='{{item.full_id}}',
            sensor_grid=create_rad_folder._outputs.model_folder,
            sky_matrix=create_total_sky._outputs.sky_matrix,
            sky_dome=create_sky_dome._outputs.sky_dome,
            sky_matrix_direct=create_direct_sky._outputs.sky_matrix,
            sunpath=generate_sunpath._outputs.sunpath,
            sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        pass

    @task(template=AnnualDaylightMetrics,
          needs=[parse_sun_up_hours, annual_daylight_raytracing])
    def calculate_annual_metrics(self,
                                 folder='results',
                                 schedule=schedule,
                                 thresholds=thresholds):
        return [{
            'from': AnnualDaylightMetrics()._outputs.annual_metrics,
            'to': 'metrics'
        }]

    results = Outputs.folder(
        source='results',
        description='Folder with raw result files (.ill) that '
        'contain illuminance matrices.',
        alias=annual_daylight_results)

    metrics = Outputs.folder(source='metrics',
                             description='Annual metrics folder.')

    da = Outputs.folder(source='metrics/da',
                        description='Daylight autonomy results.',
                        alias=daylight_autonomy_results)

    cda = Outputs.folder(source='metrics/cda',
                         description='Continuous daylight autonomy results.',
                         alias=continuous_daylight_autonomy_results)

    udi = Outputs.folder(source='metrics/udi',
                         description='Useful daylight illuminance results.',
                         alias=udi_results)

    udi_lower = Outputs.folder(
        source='metrics/udi_lower',
        description='Results for the percent of time that '
        'is below the lower threshold of useful daylight illuminance.',
        alias=udi_lower_results)

    udi_upper = Outputs.folder(
        source='metrics/udi_upper',
        description='Results for the percent of time that '
        'is above the upper threshold of useful daylight illuminance.',
        alias=udi_upper_results)
예제 #5
0
class PmvComfortMapEntryPoint(DAG):
    """PMV comfort map entry point."""

    # inputs
    model = Inputs.file(
        description='A Honeybee model in HBJSON file format.',
        extensions=['json', 'hbjson'],
        alias=hbjson_model_grid_room_input
    )

    epw = Inputs.file(
        description='EPW weather file to be used for the comfort map simulation.',
        extensions=['epw']
    )

    ddy = Inputs.file(
        description='A DDY file with design days to be used for the initial '
        'sizing calculation.', extensions=['ddy'],
        alias=ddy_input
    )

    north = Inputs.float(
        default=0,
        description='A a number between -360 and 360 for the counterclockwise '
        'difference between the North and the positive Y-axis in degrees.',
        spec={'type': 'number', 'minimum': -360, 'maximum': 360},
        alias=north_input
    )

    run_period = Inputs.str(
        description='An AnalysisPeriod string to set the start and end dates of '
        'the simulation (eg. "6/21 to 9/21 between 0 and 23 @1"). If None, '
        'the simulation will be annual.', default='', alias=run_period_input
    )

    additional_idf = Inputs.file(
        description='An IDF file with text to be appended before simulation. This '
        'input can be used to include EnergyPlus objects that are not '
        'currently supported by honeybee.', extensions=['idf'],
        optional=True, alias=additional_idf_input
    )

    cpu_count = Inputs.int(
        default=50,
        description='The maximum number of CPUs for parallel execution. This will be '
        'used to determine the number of sensors run by each worker.',
        spec={'type': 'integer', 'minimum': 1},
        alias=cpu_count
    )

    min_sensor_count = Inputs.int(
        description='The minimum number of sensors in each sensor grid after '
        'redistributing the sensors based on cpu_count. This value takes '
        'precedence over the cpu_count and can be used to ensure that '
        'the parallelization does not result in generating unnecessarily small '
        'sensor grids. The default value is set to 1, which means that the '
        'cpu_count is always respected.', default=1,
        spec={'type': 'integer', 'minimum': 1},
        alias=min_sensor_count_input
    )

    write_set_map = Inputs.str(
        description='A switch to note whether the output temperature CSV should '
        'record Operative Temperature or Standard Effective Temperature (SET). '
        'SET is relatively intense to compute and so only recording Operative '
        'Temperature can greatly reduce run time, particularly when air speeds '
        'are low. However, SET accounts for all 6 PMV model inputs and so is a '
        'more representative "feels-like" temperature for the PMV model.',
        default='write-op-map', alias=write_set_map_input,
        spec={'type': 'string', 'enum': ['write-op-map', 'write-set-map']}
    )

    air_speed = Inputs.file(
        description='A CSV file containing a single number for air speed in m/s or '
        'several rows of air speeds that align with the length of the run period. This '
        'will be used for all indoor comfort evaluation.', extensions=['txt', 'csv'],
        optional=True, alias=air_speed_input
    )

    met_rate = Inputs.file(
        description='A CSV file containing a single number for metabolic rate in met '
        'or several rows of met values that align with the length of the run period.',
        extensions=['txt', 'csv'], optional=True, alias=met_rate_input
    )

    clo_value = Inputs.file(
        description='A CSV file containing a single number for clothing level in clo '
        'or several rows of clo values that align with the length of the run period.',
        extensions=['txt', 'csv'], optional=True, alias=clo_value_input
    )

    solarcal_parameters = 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',
        alias=solar_body_par_indoor_input
    )

    comfort_parameters = Inputs.str(
        description='An PMVParameter string to customize the assumptions of '
        'the PMV comfort model.', default='--ppd-threshold 10',
        alias=pmv_comfort_par_input
    )

    radiance_parameters = Inputs.str(
        description='Radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05',
        alias=rad_par_annual_input
    )

    # tasks
    @task(template=SimParComfort)
    def create_sim_par(self, ddy=ddy, run_period=run_period, north=north) -> List[Dict]:
        return [
            {
                'from': SimParComfort()._outputs.sim_par_json,
                'to': 'energy/simulation_parameter.json'
            }
        ]

    @task(template=DynamicOutputs)
    def dynamic_construction_outputs(
        self, model=model, base_idf=additional_idf
    ) -> List[Dict]:
        return [
            {
                'from': DynamicOutputs()._outputs.dynamic_out_idf,
                'to': 'energy/additional.idf'
            }
        ]

    @task(template=SimulateModel, needs=[create_sim_par, dynamic_construction_outputs])
    def run_energy_simulation(
        self, model=model, epw=epw, sim_par=create_sim_par._outputs.sim_par_json,
        additional_idf=dynamic_construction_outputs._outputs.dynamic_out_idf
    ) -> List[Dict]:
        return [
            {'from': SimulateModel()._outputs.sql, 'to': 'energy/eplusout.sql'},
            {'from': SimulateModel()._outputs.idf, 'to': 'energy/in.idf'}
        ]

    @task(template=EpwToWea)
    def create_wea(self, epw=epw, period=run_period) -> List[Dict]:
        return [
            {
                'from': EpwToWea()._outputs.wea,
                'to': 'radiance/shortwave/in.wea'
            }
        ]

    @task(template=CreateSunMatrix, needs=[create_wea])
    def generate_sunpath(self, north=north, wea=create_wea._outputs.wea, output_type=1):
        """Create sunpath for sun-up-hours."""
        return [
            {
                'from': CreateSunMatrix()._outputs.sunpath,
                'to': 'radiance/shortwave/resources/sunpath.mtx'
            },
            {
                'from': CreateSunMatrix()._outputs.sun_modifiers,
                'to': 'radiance/shortwave/resources/suns.mod'
            }
        ]

    @task(template=CreateSkyDome)
    def create_sky_dome(self):
        """Create sky dome for daylight coefficient studies."""
        return [
            {
                'from': CreateSkyDome()._outputs.sky_dome,
                'to': 'radiance/shortwave/resources/sky.dome'
            }
        ]

    @task(template=CreateSkyMatrix, needs=[create_wea])
    def create_total_sky(
        self, north=north, wea=create_wea._outputs.wea,
        sky_type='total', output_type='solar', sun_up_hours='sun-up-hours'
    ):
        return [
            {
                'from': CreateSkyMatrix()._outputs.sky_matrix,
                'to': 'radiance/shortwave/resources/sky.mtx'
            }
        ]

    @task(template=CreateSkyMatrix, needs=[create_wea])
    def create_direct_sky(
        self, north=north, wea=create_wea._outputs.wea,
        sky_type='sun-only', output_type='solar', sun_up_hours='sun-up-hours'
    ):
        return [
            {
                'from': CreateSkyMatrix()._outputs.sky_matrix,
                'to': 'radiance/shortwave/resources/sky_direct.mtx'
            }
        ]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(self, sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        return [
            {
                'from': ParseSunUpHours()._outputs.sun_up_hours,
                'to': 'radiance/shortwave/sun-up-hours.txt'
            }
        ]

    @task(template=ModelModifiersFromConstructions)
    def set_modifiers_from_constructions(
        self, model=model, use_visible='solar', exterior_offset=0.02
    ) -> List[Dict]:
        return [
            {
                'from': ModelModifiersFromConstructions()._outputs.new_model,
                'to': 'radiance/shortwave/model.hbjson'
            }
        ]

    @task(template=CreateRadianceFolderGrid, needs=[set_modifiers_from_constructions])
    def create_rad_folder(
        self, input_model=set_modifiers_from_constructions._outputs.new_model
    ):
        """Translate the input model to a radiance folder."""
        return [
            {
                'from': CreateRadianceFolderGrid()._outputs.model_folder,
                'to': 'radiance/shortwave/model'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.sensor_grids_file,
                'to': 'results/temperature/grids_info.json'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
                'description': 'Sensor grids information.'
            }
        ]

    @task(template=CopyMultiple, needs=[create_rad_folder])
    def copy_grid_info(self, src=create_rad_folder._outputs.sensor_grids_file):
        return [
            {
                'from': CopyMultiple()._outputs.dst_1,
                'to': 'results/condition/grids_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_2,
                'to': 'results/condition_intensity/grids_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_3,
                'to': 'metrics/TCP/grids_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_4,
                'to': 'metrics/HSP/grids_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_5,
                'to': 'metrics/CSP/grids_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_6,
                'to': 'initial_results/conditions/grids_info.json'
            }
        ]

    @task(
        template=SplitGridFolder, needs=[create_rad_folder],
        sub_paths={'input_folder': 'grid'}
    )
    def split_grid_folder(
        self, input_folder=create_rad_folder._outputs.model_folder,
        cpu_count=cpu_count, cpus_per_grid=3, min_sensor_count=min_sensor_count
    ):
        """Split sensor grid folder based on the number of CPUs"""
        return [
            {
                'from': SplitGridFolder()._outputs.output_folder,
                'to': 'radiance/grid'
            },
            {
                'from': SplitGridFolder()._outputs.dist_info,
                'to': 'initial_results/results/temperature/_redist_info.json'
            },
            {
                'from': SplitGridFolder()._outputs.sensor_grids_file,
                'to': 'radiance/grid/_split_info.json'
            },
            {
                'from': SplitGridFolder()._outputs.sensor_grids,
                'description': 'Sensor grids information.'
            }
        ]

    @task(template=CopyMultiple, needs=[split_grid_folder])
    def copy_redist_info(self, src=split_grid_folder._outputs.dist_info):
        return [
            {
                'from': CopyMultiple()._outputs.dst_1,
                'to': 'initial_results/results/condition/_redist_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_2,
                'to': 'initial_results/results/condition_intensity/_redist_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_3,
                'to': 'initial_results/metrics/TCP/_redist_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_4,
                'to': 'initial_results/metrics/HSP/_redist_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_5,
                'to': 'initial_results/metrics/CSP/_redist_info.json'
            },
            {
                'from': CopyMultiple()._outputs.dst_6,
                'to': 'initial_results/conditions/_redist_info.json'
            }
        ]

    @task(template=CreateOctree, needs=[create_rad_folder])
    def create_octree(self, model=create_rad_folder._outputs.model_folder):
        """Create octree from radiance folder."""
        return [
            {
                'from': CreateOctree()._outputs.scene_file,
                'to': 'radiance/shortwave/resources/scene.oct'
            }
        ]

    @task(
        template=CreateOctreeWithSky, needs=[generate_sunpath, create_rad_folder]
    )
    def create_octree_with_suns(
        self, model=create_rad_folder._outputs.model_folder,
        sky=generate_sunpath._outputs.sunpath
    ):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [
            {
                'from': CreateOctreeWithSky()._outputs.scene_file,
                'to': 'radiance/shortwave/resources/scene_with_suns.oct'
            }
        ]

    @task(
        template=CreateOctreeAbstractedGroups,
        needs=[generate_sunpath, create_rad_folder]
    )
    def create_dynamic_octrees(
        self, model=create_rad_folder._outputs.model_folder,
        sunpath=generate_sunpath._outputs.sunpath
    ):
        """Create a set of octrees for each dynamic window construction."""
        return [
            {
                'from': CreateOctreeAbstractedGroups()._outputs.scene_folder,
                'to': 'radiance/shortwave/resources/dynamic_groups'
            },
            {
                'from': CreateOctreeAbstractedGroups()._outputs.scene_info,
                'description': 'List of octrees to iterate over.'
            }
        ]

    @task(
        template=CreateOctreeShadeTransmittance,
        needs=[generate_sunpath, create_rad_folder]
    )
    def create_shade_trans_octrees(
        self, model=create_rad_folder._outputs.model_folder,
        sunpath=generate_sunpath._outputs.sunpath
    ):
        """Create a set of octrees for each dynamic shade."""
        return [
            {
                'from': CreateOctreeShadeTransmittance()._outputs.scene_folder,
                'to': 'radiance/shortwave/resources/dynamic_shades'
            },
            {
                'from': CreateOctreeShadeTransmittance()._outputs.scene_info,
                'description': 'List of octrees to iterate over.'
            }
        ]

    @task(template=ModelTransSchedules)
    def create_model_trans_schedules(self, model=model, period=run_period) -> List[Dict]:
        return [
            {
                'from': ModelTransSchedules()._outputs.trans_schedule_json,
                'to': 'radiance/shortwave/resources/trans_schedules.json'
            }
        ]

    @task(template=ViewFactorModifiers)
    def create_view_factor_modifiers(
        self, model=model, include_sky='include', include_ground='include',
        grouped_shades='grouped'
    ):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [
            {
                'from': ViewFactorModifiers()._outputs.modifiers_file,
                'to': 'radiance/longwave/resources/scene.mod'
            },
            {
                'from': ViewFactorModifiers()._outputs.scene_file,
                'to': 'radiance/longwave/resources/scene.oct'
            }
        ]

    @task(template=ModelOccSchedules)
    def create_model_occ_schedules(self, model=model, period=run_period) -> List[Dict]:
        return [
            {
                'from': ModelOccSchedules()._outputs.occ_schedule_json,
                'to': 'metrics/occupancy_schedules.json'
            }
        ]

    @task(
        template=RadianceMappingEntryPoint,
        needs=[
            create_sky_dome, create_octree_with_suns, create_octree, generate_sunpath,
            create_total_sky, create_direct_sky, create_rad_folder, split_grid_folder,
            create_view_factor_modifiers
        ],
        loop=split_grid_folder._outputs.sensor_grids,
        sub_folder='radiance',
        sub_paths={'sensor_grid': '{{item.full_id}}.pts'}
    )
    def run_radiance_simulation(
        self,
        radiance_parameters=radiance_parameters,
        model=model,
        octree_file_with_suns=create_octree_with_suns._outputs.scene_file,
        octree_file=create_octree._outputs.scene_file,
        octree_file_view_factor=create_view_factor_modifiers._outputs.scene_file,
        grid_name='{{item.full_id}}',
        sensor_grid=split_grid_folder._outputs.output_folder,
        sensor_count='{{item.count}}',
        sky_dome=create_sky_dome._outputs.sky_dome,
        sky_matrix=create_total_sky._outputs.sky_matrix,
        sky_matrix_direct=create_direct_sky._outputs.sky_matrix,
        sun_modifiers=generate_sunpath._outputs.sun_modifiers,
        view_factor_modifiers=create_view_factor_modifiers._outputs.modifiers_file
    ) -> List[Dict]:
        pass

    @task(
        template=DynamicShadeContribEntryPoint,
        needs=[
            create_sky_dome, generate_sunpath, parse_sun_up_hours,
            create_total_sky, create_direct_sky,
            split_grid_folder, create_shade_trans_octrees, run_radiance_simulation
        ],
        loop=create_shade_trans_octrees._outputs.scene_info,
        sub_folder='radiance',
        sub_paths={
            'octree_file': '{{item.default}}',
            'octree_file_with_suns': '{{item.sun}}'
        }
    )
    def run_radiance_shade_contribution(
        self,
        radiance_parameters=radiance_parameters,
        octree_file=create_shade_trans_octrees._outputs.scene_folder,
        octree_file_with_suns=create_shade_trans_octrees._outputs.scene_folder,
        group_name='{{item.identifier}}',
        sensor_grid_folder='radiance/shortwave/grids',
        sensor_grids=split_grid_folder._outputs.sensor_grids_file,
        sky_dome=create_sky_dome._outputs.sky_dome,
        sky_matrix=create_total_sky._outputs.sky_matrix,
        sky_matrix_direct=create_direct_sky._outputs.sky_matrix,
        sun_modifiers=generate_sunpath._outputs.sun_modifiers,
        sun_up_hours=parse_sun_up_hours._outputs.sun_up_hours
    ) -> List[Dict]:
        pass

    @task(
        template=DynamicContributionEntryPoint,
        needs=[
            create_sky_dome, generate_sunpath, parse_sun_up_hours,
            create_total_sky, create_direct_sky,
            split_grid_folder, create_dynamic_octrees,
            run_energy_simulation, run_radiance_simulation
        ],
        loop=create_dynamic_octrees._outputs.scene_info,
        sub_folder='radiance',
        sub_paths={
            'octree_file_spec': '{{item.identifier}}/{{item.spec}}',
            'octree_file_diff': '{{item.identifier}}/{{item.diff}}',
            'octree_file_with_suns': '{{item.identifier}}/{{item.sun}}'
        },
    )
    def run_radiance_dynamic_contribution(
        self,
        radiance_parameters=radiance_parameters,
        result_sql=run_energy_simulation._outputs.sql,
        octree_file_spec=create_dynamic_octrees._outputs.scene_folder,
        octree_file_diff=create_dynamic_octrees._outputs.scene_folder,
        octree_file_with_suns=create_dynamic_octrees._outputs.scene_folder,
        group_name='{{item.identifier}}',
        sensor_grid_folder='radiance/shortwave/grids',
        sensor_grids=split_grid_folder._outputs.sensor_grids_file,
        sky_dome=create_sky_dome._outputs.sky_dome,
        sky_matrix=create_total_sky._outputs.sky_matrix,
        sky_matrix_direct=create_direct_sky._outputs.sky_matrix,
        sun_modifiers=generate_sunpath._outputs.sun_modifiers,
        sun_up_hours=parse_sun_up_hours._outputs.sun_up_hours,
    ) -> List[Dict]:
        pass

    @task(
        template=ComfortMappingEntryPoint,
        needs=[
            parse_sun_up_hours, create_view_factor_modifiers,
            create_model_occ_schedules, create_model_trans_schedules,
            run_energy_simulation, run_radiance_simulation, split_grid_folder,
            run_radiance_dynamic_contribution, run_radiance_shade_contribution
        ],
        loop=split_grid_folder._outputs.sensor_grids,
        sub_folder='initial_results',
        sub_paths={
            'enclosure_info': '{{item.full_id}}.json',
            'view_factors': '{{item.full_id}}.csv',
            'indirect_irradiance': '{{item.full_id}}.ill',
            'direct_irradiance': '{{item.full_id}}.ill',
            'ref_irradiance': '{{item.full_id}}.ill'
        }
    )
    def run_comfort_map(
        self,
        epw=epw,
        result_sql=run_energy_simulation._outputs.sql,
        grid_name='{{item.full_id}}',
        enclosure_info='radiance/enclosures',
        view_factors='radiance/longwave/view_factors',
        modifiers=create_view_factor_modifiers._outputs.modifiers_file,
        indirect_irradiance='radiance/shortwave/results/indirect',
        direct_irradiance='radiance/shortwave/results/direct',
        ref_irradiance='radiance/shortwave/results/reflected',
        sun_up_hours=parse_sun_up_hours._outputs.sun_up_hours,
        contributions='radiance/shortwave/dynamic/final/{{item.full_id}}',
        transmittance_contribs='radiance/shortwave/shd_trans/final/{{item.full_id}}',
        trans_schedules=create_model_trans_schedules._outputs.trans_schedule_json,
        occ_schedules=create_model_occ_schedules._outputs.occ_schedule_json,
        run_period=run_period,
        air_speed=air_speed,
        met_rate=met_rate,
        clo_value=clo_value,
        solarcal_par=solarcal_parameters,
        comfort_par=comfort_parameters,
        write_set_map=write_set_map
    ) -> List[Dict]:
        pass

    @task(template=MergeFolderData, needs=[run_comfort_map])
    def restructure_temperature_results(
        self, input_folder='initial_results/results/temperature', extension='csv'
    ):
        return [
            {
                'from': MergeFolderData()._outputs.output_folder,
                'to': 'results/temperature'
            }
        ]

    @task(template=MergeFolderData, needs=[run_comfort_map])
    def restructure_condition_results(
        self, input_folder='initial_results/results/condition', extension='csv'
    ):
        return [
            {
                'from': MergeFolderData()._outputs.output_folder,
                'to': 'results/condition'
            }
        ]

    @task(template=MergeFolderData, needs=[run_comfort_map])
    def restructure_condition_intensity_results(
        self, input_folder='initial_results/results/condition_intensity', extension='csv'
    ):
        return [
            {
                'from': MergeFolderData()._outputs.output_folder,
                'to': 'results/condition_intensity'
            }
        ]

    @task(template=MergeFolderData, needs=[run_comfort_map])
    def restructure_tcp_results(
        self, input_folder='initial_results/metrics/TCP', extension='csv'
    ):
        return [
            {
                'from': MergeFolderData()._outputs.output_folder,
                'to': 'metrics/TCP'
            }
        ]

    @task(template=MergeFolderData, needs=[run_comfort_map])
    def restructure_hsp_results(
        self, input_folder='initial_results/metrics/HSP', extension='csv'
    ):
        return [
            {
                'from': MergeFolderData()._outputs.output_folder,
                'to': 'metrics/HSP'
            }
        ]

    @task(template=MergeFolderData, needs=[run_comfort_map])
    def restructure_csp_results(
        self, input_folder='initial_results/metrics/CSP', extension='csv'
    ):
        return [
            {
                'from': MergeFolderData()._outputs.output_folder,
                'to': 'metrics/CSP'
            }
        ]

    @task(template=MapResultInfo)
    def create_result_info(
        self, comfort_model='pmv', run_period=run_period, qualifier=write_set_map
    ) -> List[Dict]:
        return [
            {
                'from': MapResultInfo()._outputs.viz_config_file,
                'to': 'metrics/config.json'
            },
            {
                'from': MapResultInfo()._outputs.temperature_info,
                'to': 'results/temperature/results_info.json'
            },
            {
                'from': MapResultInfo()._outputs.condition_info,
                'to': 'results/condition/results_info.json'
            },
            {
                'from': MapResultInfo()._outputs.condition_intensity_info,
                'to': 'results/condition_intensity/results_info.json'
            }
        ]

    @task(template=Copy, needs=[create_result_info])
    def copy_result_info(
        self, src=create_result_info._outputs.temperature_info
    ) -> List[Dict]:
        return [
            {
                'from': Copy()._outputs.dst,
                'to': 'initial_results/conditions/results_info.json'
            }
        ]

    # outputs
    environmental_conditions = Outputs.folder(
        source='initial_results/conditions',
        description='A folder containing the environmental conditions that were input '
        'to the thermal comfort model. This include the MRT, air temperature, longwave '
        'MRT, shortwave MRT delta and relative humidity.', alias=env_conditions_output
    )

    temperature = Outputs.folder(
        source='results/temperature', description='A folder containing CSV maps of '
        'Operative Temperature for each sensor grid. Alternatively, if the '
        'write-set-map option is used, the CSV maps here will contain Standard '
        'Effective Temperature (SET). Values are in Celsius.',
        alias=operative_or_set_output
    )

    condition = Outputs.folder(
        source='results/condition', description='A folder containing CSV maps of '
        'comfort conditions for each sensor grid. -1 indicates unacceptably cold '
        'conditions. +1 indicates unacceptably hot conditions. 0 indicates neutral '
        '(comfortable) conditions.', alias=thermal_condition_output
    )

    pmv = Outputs.folder(
        source='results/condition_intensity', description='A folder containing CSV maps '
        'of the Predicted Mean Vote (PMV) for each sensor grid. This can be used '
        'to understand not just whether conditions are acceptable but how '
        'uncomfortably hot or cold they are.', alias=pmv_output
    )

    tcp = Outputs.folder(
        source='metrics/TCP', description='A folder containing CSV values for Thermal '
        'Comfort Percent (TCP). TCP is the percentage of occupied time where '
        'thermal conditions are acceptable/comfortable.', alias=tcp_output
    )

    hsp = Outputs.folder(
        source='metrics/HSP', description='A folder containing CSV values for Heat '
        'Sensation Percent (HSP). HSP is the percentage of occupied time where '
        'thermal conditions are hotter than what is considered acceptable/comfortable.',
        alias=hsp_output
    )

    csp = Outputs.folder(
        source='metrics/CSP', description='A folder containing CSV values for Cold '
        'Sensation Percent (CSP). CSP is the percentage of occupied time where '
        'thermal conditions are colder than what is considered acceptable/comfortable.',
        alias=csp_output
    )
예제 #6
0
class PointInTimeGridRayTracing(DAG):
    """Point-in-time grid-based ray tracing."""
    # inputs

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution',
        spec={
            'type': 'integer',
            'minimum': 1
        })

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing',
        default='-ab 2 -aa 0.1 -ad 2048 -ar 64')

    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']
        })

    octree_file = Inputs.file(description='A Radiance octree file.',
                              extensions=['oct'])

    grid_name = Inputs.str(
        description=
        'Sensor grid file name. This is useful to rename the final result '
        'file to {grid_name}.res')

    sensor_grid = Inputs.file(description='Sensor grid file.',
                              extensions=['pts'])

    bsdfs = Inputs.folder(
        description='Folder containing any BSDF files needed for ray tracing.')

    @task(template=SplitGrid)
    def split_grid(self, sensor_count=sensor_count, input_grid=sensor_grid):
        return [{
            'from': SplitGrid()._outputs.grids_list
        }, {
            'from': SplitGrid()._outputs.output_folder,
            'to': 'sub_grids'
        }]

    @task(template=RayTracingPointInTime,
          needs=[split_grid],
          loop=split_grid._outputs.grids_list,
          sub_folder='results',
          sub_paths={'grid': '{{item.path}}'})
    def ray_tracing(self,
                    radiance_parameters=radiance_parameters,
                    metric=metric,
                    grid=split_grid._outputs.output_folder,
                    scene_file=octree_file,
                    bsdf_folder=bsdfs):
        return [{
            'from': RayTracingPointInTime()._outputs.result,
            'to': '{{item.name}}.res'
        }]

    @task(template=MergeFiles, needs=[ray_tracing])
    def merge_results(self,
                      name=grid_name,
                      extension='.res',
                      folder='results'):
        return [{
            'from': MergeFiles()._outputs.result_file,
            'to': '../../results/{{self.name}}.res'
        }]
예제 #7
0
class AnnualRadiationRayTracing(DAG):
    # inputs

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution',
        spec={
            'type': 'integer',
            'minimum': 1
        })

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing', default='-ab 2')

    octree_file_with_suns = Inputs.file(
        description='A Radiance octree file with suns.', extensions=['oct'])

    octree_file = Inputs.file(description='A Radiance octree file.',
                              extensions=['oct'])

    grid_name = Inputs.str(
        description=
        'Sensor grid file name. This is useful to rename the final result '
        'file to {grid_name}.res')

    sensor_grid = Inputs.file(description='Sensor grid file.',
                              extensions=['pts'])

    sun_modifiers = Inputs.file(description='A file with sun modifiers.')

    sky_matrix_indirect = Inputs.file(
        description='Path to indirect skymtx file (i.e. gendaymtx -s).')

    sky_dome = Inputs.file(description='Path to sky dome file.')

    @task(template=SplitGrid)
    def split_grid(self, sensor_count=sensor_count, input_grid=sensor_grid):
        return [{
            'from': SplitGrid()._outputs.grids_list
        }, {
            'from': SplitGrid()._outputs.output_folder,
            'to': '00_sub_grids'
        }]

    @task(template=DaylightContribution,
          needs=[split_grid],
          loop=split_grid._outputs.grids_list,
          sub_folder='01_direct',
          sub_paths={'sensor_grid': '{{item.path}}'})
    def direct_sunlight(
        self,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -ab 0 -dc 1.0 -dt 0.0 -dj 0.0 -dr 0',
        sensor_count='{{item.count}}',
        modifiers=sun_modifiers,
        sensor_grid=split_grid._outputs.output_folder,
        conversion='0.265 0.670 0.065',
        output_format='a',  # make it ascii so we can expose the file as a separate output
        scene_file=octree_file_with_suns):
        return [{
            'from': DaylightContribution()._outputs.result_file,
            'to': '{{item.name}}.ill'
        }]

    @task(template=DaylightCoefficient,
          needs=[split_grid],
          loop=split_grid._outputs.grids_list,
          sub_folder='02_indirect',
          sub_paths={'sensor_grid': '{{item.path}}'})
    def indirect_sky(
            self,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -c 1',
            sensor_count='{{item.count}}',
            sky_matrix=sky_matrix_indirect,
            sky_dome=sky_dome,
            sensor_grid=split_grid._outputs.output_folder,
            conversion='0.265 0.670 0.065',  # divide by 179
            scene_file=octree_file):
        return [{
            'from': DaylightContribution()._outputs.result_file,
            'to': '{{item.name}}.ill'
        }]

    @task(template=AddSkyMatrix,
          needs=[split_grid, direct_sunlight, indirect_sky],
          loop=split_grid._outputs.grids_list,
          sub_folder='03_total')
    def output_matrix_math(
        self,
        indirect_sky_matrix='02_indirect/{{item.name}}.ill',
        sunlight_matrix='01_direct/{{item.name}}.ill',
    ):
        return [{
            'from': AddSkyMatrix()._outputs.results_file,
            'to': '{{item.name}}.ill'
        }]

    @task(template=MergeFiles, needs=[output_matrix_math])
    def merge_total_results(self,
                            name=grid_name,
                            extension='.ill',
                            folder='03_total'):
        return [{
            'from': MergeFiles()._outputs.result_file,
            'to': '../../results/total/{{self.name}}.ill'
        }]

    @task(template=MergeFiles, needs=[output_matrix_math])
    def merge_direct_results(self,
                             name=grid_name,
                             extension='.ill',
                             folder='01_direct'):
        return [{
            'from': MergeFiles()._outputs.result_file,
            'to': '../../results/direct/{{self.name}}.ill'
        }]
class DirectSunHoursCalculation(DAG):

    sun_modifiers = Inputs.file(description='A file with sun modifiers.')

    sensor_grid = Inputs.file(description='Sensor grid file.',
                              extensions=['pts'])

    octree_file = Inputs.file(description='A Radiance octree file with suns.',
                              extensions=['oct'])

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution',
        spec={
            'type': 'integer',
            'minimum': 1
        })

    grid_name = Inputs.str(
        description=
        'Sensor grid file name. This is useful to rename the final result '
        'file to {grid_name}.ill')

    @task(template=DaylightContribution, sub_folder='direct-radiation')
    def direct_radiation_calculation(
            self,
            fixed_radiance_parameters='-aa 0.0 -I -faa -ab 0 -dc 1.0 -dt 0.0 -dj 0.0 -dr 0',
            conversion='0.265 0.670 0.065',
            sensor_count=sensor_count,
            modifiers=sun_modifiers,
            sensor_grid=sensor_grid,
            grid_name=grid_name,
            scene_file=octree_file):
        return [{
            'from': DaylightContribution()._outputs.result_file,
            'to': '{{self.grid_name}}.ill'
        }]

    @task(template=ConvertToBinary,
          needs=[direct_radiation_calculation],
          sub_folder='direct-sun-hours')
    def convert_to_sun_hours(
            self,
            input_mtx=direct_radiation_calculation._outputs.result_file,
            grid_name=grid_name):
        return [{
            'from': ConvertToBinary()._outputs.output_mtx,
            'to': '{{self.grid_name}}.ill'
        }]

    @task(template=SumRow,
          needs=[convert_to_sun_hours],
          sub_folder='cumulative-sun-hours')
    def calculate_cumulative_hours(
            self,
            input_mtx=convert_to_sun_hours._outputs.output_mtx,
            grid_name=grid_name):
        return [{
            'from': SumRow()._outputs.output_mtx,
            'to': '{{self.grid_name}}.res'
        }]
class AnnualSkyRadiationRayTracing(DAG):
    # inputs

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution',
        spec={'type': 'integer', 'minimum': 1}
    )

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing',
        default='-ab 2 -ad 5000 -lw 2e-05'
    )

    octree_file = Inputs.file(
        description='A Radiance octree file without suns or sky.',
        extensions=['oct']
    )

    grid_name = Inputs.str(
        description='Sensor grid file name. This is useful to rename the final result '
        'file to {grid_name}.res'
    )

    sensor_grid = Inputs.file(
        description='Sensor grid file.',
        extensions=['pts']
    )

    sky_matrix = Inputs.file(
        description='Path to skymtx file.'
    )

    sky_dome = Inputs.file(
        description='Path to sky dome file.'
    )

    order_by = Inputs.str(
        description='Order of the output results. By default the results are ordered '
        'to include the results for a single sensor in each row.', default='sensor',
        spec={'type': 'string', 'enum': ['sensor', 'datetime']}
    )

    @task(template=SplitGrid)
    def split_grid(self, sensor_count=sensor_count, input_grid=sensor_grid):
        return [
            {'from': SplitGrid()._outputs.grids_list},
            {'from': SplitGrid()._outputs.output_folder, 'to': '00_sub_grids'}
        ]

    # TODO: add a step to set divide_by to 1/timestep if  sky is cumulative.
    @task(
        template=DaylightCoefficient, needs=[split_grid],
        loop=split_grid._outputs.grids_list, sub_folder='01_radiation',
        sub_paths={'sensor_grid': '{{item.path}}'}
    )
    def total_sky(
        self,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -c 1',
        sensor_count='{{item.count}}',
        sky_matrix=sky_matrix, sky_dome=sky_dome,
        sensor_grid=split_grid._outputs.output_folder,
        conversion='0.265 0.670 0.065',  # divide by 179
        scene_file=octree_file,
        output_format='a',
        order_by=order_by
            ):
        return [
            {
                'from': DaylightContribution()._outputs.result_file,
                'to': '{{item.name}}.ill'
            }
        ]

    @task(
        template=MergeFiles, needs=[total_sky]
    )
    def merge_direct_results(
            self, name=grid_name, extension='.ill', folder='01_radiation'):
        return [
            {
                'from': MergeFiles()._outputs.result_file,
                'to': '../../results/{{self.name}}.ill'
            }
        ]
예제 #10
0
class AnnualDaylightRayTracing(DAG):
    # inputs

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution',
        spec={'type': 'integer', 'minimum': 1}
    )

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing',
        default='-ab 2 -ad 5000 -lw 2e-05'
    )

    octree_file_with_suns = Inputs.file(
        description='A Radiance octree file with suns.',
        extensions=['oct']
    )

    octree_file = Inputs.file(
        description='A Radiance octree file.',
        extensions=['oct']
    )

    grid_name = Inputs.str(
        description='Sensor grid file name. This is useful to rename the final result '
        'file to {grid_name}.res'
    )

    sensor_grid = Inputs.file(
        description='Sensor grid file.',
        extensions=['pts']
    )

    sun_modifiers = Inputs.file(
        description='A file with sun modifiers.'
    )

    sky_matrix = Inputs.file(
        description='Path to total sky matrix file.'
    )

    sky_matrix_direct = Inputs.file(
        description='Path to direct skymtx file (i.e. gendaymtx -d).'
    )

    sky_dome = Inputs.file(
        description='Path to sky dome file.'
    )

    @task(template=SplitGrid)
    def split_grid(self, sensor_count=sensor_count, input_grid=sensor_grid):
        return [
            {'from': SplitGrid()._outputs.grids_list},
            {'from': SplitGrid()._outputs.output_folder, 'to': 'sub_grids'}
        ]

    @task(
        template=DaylightContribution, needs=[split_grid],
        loop=split_grid._outputs.grids_list, sub_folder='direct_sunlight',
        sub_paths={'sensor_grid': '{{item.path}}'}
    )
    def direct_sunlight(
        self,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -faf -ab 0 -dc 1.0 -dt 0.0 -dj 0.0 -dr 0',
        sensor_count='{{item.count}}', modifiers=sun_modifiers,
        sensor_grid=split_grid._outputs.output_folder,
        scene_file=octree_file_with_suns
            ):
        return [
            {
                'from': DaylightContribution()._outputs.result_file,
                'to': '{{item.name}}.ill'
            }
        ]

    @task(
        template=DaylightCoefficient, needs=[split_grid],
        loop=split_grid._outputs.grids_list, sub_folder='direct_sky',
        sub_paths={'sensor_grid': '{{item.path}}'}
    )
    def direct_sky(
        self,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -ab 1 -c 1 -faf',
        sensor_count='{{item.count}}',
        sky_matrix=sky_matrix_direct, sky_dome=sky_dome,
        sensor_grid=split_grid._outputs.output_folder,
        scene_file=octree_file
            ):
        return [
            {
                'from': DaylightContribution()._outputs.result_file,
                'to': '{{item.name}}.ill'
            }
        ]

    @task(
        template=DaylightCoefficient, needs=[split_grid],
        loop=split_grid._outputs.grids_list, sub_folder='total_sky',
        sub_paths={'sensor_grid': '{{item.path}}'}
    )
    def total_sky(
        self,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -c 1 -faf',
        sensor_count='{{item.count}}',
        sky_matrix=sky_matrix, sky_dome=sky_dome,
        sensor_grid=split_grid._outputs.output_folder,
        scene_file=octree_file
            ):
        return [
            {
                'from': DaylightContribution()._outputs.result_file,
                'to': '{{item.name}}.ill'
            }
        ]

    @task(
        template=AddRemoveSkyMatrix,
        needs=[split_grid, direct_sunlight, total_sky, direct_sky],
        loop=split_grid._outputs.grids_list, sub_folder='final'
    )
    def output_matrix_math(
        self,
        direct_sky_matrix='direct_sky/{{item.name}}.ill',
        total_sky_matrix='total_sky/{{item.name}}.ill',
        sunlight_matrix='direct_sunlight/{{item.name}}.ill',
        conversion='47.4 119.9 11.6'
            ):
        return [
            {
                'from': AddRemoveSkyMatrix()._outputs.results_file,
                'to': '{{item.name}}.ill'
            }
        ]

    @task(
        template=MergeFiles, needs=[output_matrix_math]
    )
    def merge_raw_results(self, name=grid_name, extension='.ill', folder='final'):
        return [
            {
                'from': MergeFiles()._outputs.result_file,
                'to': '../../results/{{self.name}}.ill'
            }
        ]
예제 #11
0
class AnnualDaylightRayTracing(DAG):
    # inputs

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing',
        default='-ab 2 -ad 5000 -lw 2e-05')

    octree_file_with_suns = Inputs.file(
        description='A Radiance octree file with suns.', extensions=['oct'])

    octree_file = Inputs.file(description='A Radiance octree file.',
                              extensions=['oct'])

    grid_name = Inputs.str(
        description=
        'Sensor grid file name. This is useful to rename the final result '
        'file to {grid_name}.ill')

    sensor_grid = Inputs.file(description='Sensor grid file.',
                              extensions=['pts'])

    sensor_count = Inputs.int(
        description='Number of sensors in the input sensor grid.')

    sun_modifiers = Inputs.file(description='A file with sun modifiers.')

    sky_matrix = Inputs.file(description='Path to total sky matrix file.')

    sky_matrix_direct = Inputs.file(
        description='Path to direct skymtx file (i.e. gendaymtx -d).')

    sky_dome = Inputs.file(description='Path to sky dome file.')

    bsdfs = Inputs.folder(
        description='Folder containing any BSDF files needed for ray tracing.',
        optional=True)

    @task(template=DaylightContribution)
    def direct_sunlight(
            self,
            name=grid_name,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -ab 0 -dc 1.0 -dt 0.0 -dj 0.0 -dr 0',
            sensor_count=sensor_count,
            modifiers=sun_modifiers,
            sensor_grid=sensor_grid,
            output_format='a',  # make it ascii so we expose the file as a separate output
            scene_file=octree_file_with_suns,
            bsdf_folder=bsdfs):
        return [{
            'from': DaylightContribution()._outputs.result_file,
            'to': '../final/direct/{{self.name}}.ill'
        }]

    @task(template=DaylightCoefficient)
    def direct_sky(self,
                   radiance_parameters=radiance_parameters,
                   fixed_radiance_parameters='-aa 0.0 -I -ab 1 -c 1 -faf',
                   sensor_count=sensor_count,
                   sky_matrix=sky_matrix_direct,
                   sky_dome=sky_dome,
                   sensor_grid=sensor_grid,
                   scene_file=octree_file,
                   bsdf_folder=bsdfs):
        return [{
            'from': DaylightCoefficient()._outputs.result_file,
            'to': 'direct_sky.ill'
        }]

    @task(template=DaylightCoefficient)
    def total_sky(self,
                  radiance_parameters=radiance_parameters,
                  fixed_radiance_parameters='-aa 0.0 -I -c 1 -faf',
                  sensor_count=sensor_count,
                  sky_matrix=sky_matrix,
                  sky_dome=sky_dome,
                  sensor_grid=sensor_grid,
                  scene_file=octree_file,
                  bsdf_folder=bsdfs):
        return [{
            'from': DaylightCoefficient()._outputs.result_file,
            'to': 'total_sky.ill'
        }]

    @task(template=AddRemoveSkyMatrix,
          needs=[direct_sunlight, total_sky, direct_sky])
    def output_matrix_math(
            self,
            name=grid_name,
            direct_sky_matrix=direct_sky._outputs.result_file,
            total_sky_matrix=total_sky._outputs.result_file,
            sunlight_matrix=direct_sunlight._outputs.result_file,
            conversion='47.4 119.9 11.6'):
        return [{
            'from': AddRemoveSkyMatrix()._outputs.results_file,
            'to': '../final/total/{{self.name}}.ill'
        }]
예제 #12
0
class ShadeContribEntryPoint(DAG):
    """Entry point for Radiance calculations for comfort mapping."""

    # inputs
    radiance_parameters = Inputs.str(
        description='Radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05',
    )

    octree_file = Inputs.file(
        description=
        'A Radiance octree file with a completely transparent version '
        'of the dynamic shade group.',
        extensions=['oct'])

    octree_file_with_suns = Inputs.file(
        description='A Radiance octree file with sun modifiers.',
        extensions=['oct'])

    group_name = Inputs.str(
        description='Name for the dynamic aperture group being simulated.')

    grid_name = Inputs.str(
        description=
        'Sensor grid file name (used to name the final result files).')

    sensor_grid = Inputs.file(description='Sensor grid file.',
                              extensions=['pts'])

    ref_sensor_grid = Inputs.file(description='Reflected Sensor grid file.',
                                  extensions=['pts'])

    sensor_count = Inputs.int(
        description='Number of sensors in the input sensor grid.')

    sky_dome = Inputs.file(description='Path to sky dome file.')

    sky_matrix = Inputs.file(description='Path to total sky matrix file.')

    sky_matrix_direct = Inputs.file(
        description='Path to direct skymtx file (gendaymtx -d).')

    sun_modifiers = Inputs.file(description='A file with sun modifiers.')

    sun_up_hours = Inputs.file(
        description=
        'A sun-up-hours.txt file output by Radiance and aligns with the '
        'input irradiance files.')

    @task(template=DaylightContribution)
    def direct_sun_shade_group(
        self,
        grid=grid_name,
        group=group_name,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -ab 0 -dc 1.0 -dt 0.0 -dj 0.0 -dr 0',
        sensor_count=sensor_count,
        modifiers=sun_modifiers,
        sensor_grid=sensor_grid,
        conversion='0.265 0.670 0.065',
        output_format='a',  # make it ascii so we expose the file as a separate output
        header='remove',  # remove header to make it process-able later
        scene_file=octree_file_with_suns):
        return [{
            'from': DaylightContribution()._outputs.result_file,
            'to': 'shd_trans/final/{{self.grid}}/{{self.group}}/direct.ill'
        }]

    @task(template=DaylightCoefficient)
    def direct_sky_shade_group(
            self,
            grid=grid_name,
            group=group_name,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -ab 1 -c 1 -faf',
            sensor_count=sensor_count,
            sky_matrix=sky_matrix_direct,
            sky_dome=sky_dome,
            sensor_grid=sensor_grid,
            conversion='0.265 0.670 0.065',  # divide by 179
            scene_file=octree_file):
        return [{
            'from':
            DaylightCoefficient()._outputs.result_file,
            'to':
            'shd_trans/initial/{{self.group}}/direct_sky/{{self.grid}}.ill'
        }]

    @task(template=DaylightCoefficient)
    def total_sky_spec_shade_group(
            self,
            grid=grid_name,
            group=group_name,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -c 1 -faf',
            sensor_count=sensor_count,
            sky_matrix=sky_matrix,
            sky_dome=sky_dome,
            sensor_grid=sensor_grid,
            conversion='0.265 0.670 0.065',  # divide by 179
            scene_file=octree_file):
        return [{
            'from':
            DaylightCoefficient()._outputs.result_file,
            'to':
            'shd_trans/initial/{{self.group}}/total_sky/{{self.grid}}.ill'
        }]

    @task(template=SubtractSkyMatrix,
          needs=[total_sky_spec_shade_group, direct_sky_shade_group])
    def output_matrix_math_shade_group(
            self,
            grid=grid_name,
            group=group_name,
            total_sky_matrix=total_sky_spec_shade_group._outputs.result_file,
            direct_sky_matrix=direct_sky_shade_group._outputs.result_file):
        return [{
            'from':
            SubtractSkyMatrix()._outputs.results_file,
            'to':
            'shd_trans/final/{{self.grid}}/{{self.group}}/indirect.ill'
        }]

    @task(template=DaylightCoefficient)
    def ground_reflected_sky_shade_group(
            self,
            grid=grid_name,
            group=group_name,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -c 1',
            sensor_count=sensor_count,
            sky_matrix=sky_matrix,
            sky_dome=sky_dome,
            sensor_grid=ref_sensor_grid,
            conversion='0.265 0.670 0.065',  # divide by 179
            output_format='a',  # make it ascii so we expose the file as a separate output
            header='remove',  # remove header to make it process-able later
            scene_file=octree_file):
        return [{
            'from':
            DaylightCoefficient()._outputs.result_file,
            'to':
            'shd_trans/final/{{self.grid}}/{{self.group}}/reflected.ill'
        }]
예제 #13
0
class ComfortMappingEntryPoint(DAG):
    """Entry point for Comfort calculations."""

    # inputs
    epw = Inputs.file(
        description='Weather file used for the comfort map.',
        extensions=['epw']
    )

    result_sql = Inputs.file(
        description='A SQLite file that was generated by EnergyPlus and contains '
        'hourly or sub-hourly thermal comfort results.',
        extensions=['sql', 'db', 'sqlite']
    )

    grid_name = Inputs.str(
        description='Sensor grid file name (used to name the final result files).'
    )

    enclosure_info = Inputs.file(
        description='A JSON file containing information about the radiant '
        'enclosure that sensor points belong to.',
        extensions=['json']
    )

    view_factors = Inputs.file(
        description='A CSV of spherical view factors to the surfaces in the result-sql.',
        extensions=['csv']
    )

    modifiers = Inputs.file(
        description='Path to a modifiers file that aligns with the view-factors.',
        extensions=['mod', 'txt']
    )

    indirect_irradiance = Inputs.file(
        description='An .ill containing the indirect irradiance for each sensor.',
        extensions=['ill', 'irr']
    )

    direct_irradiance = Inputs.file(
        description='An .ill containing direct irradiance for each sensor.',
        extensions=['ill', 'irr']
    )

    ref_irradiance = Inputs.file(
        description='An .ill containing ground-reflected irradiance for each '
        'sensor.', 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.'
    )

    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 group 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.',
        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.', optional=True
    )

    trans_schedules = Inputs.file(
        description='A schedule JSON that contains fractional schedule values '
        'for each shade transmittance schedule in the model.'
    )

    occ_schedules = Inputs.file(
        description='A JSON file containing occupancy schedules derived from '
        'the input model.'
    )

    run_period = Inputs.str(
        description='An AnalysisPeriod string to set the start and end dates of '
        'the simulation (eg. "6/21 to 9/21 between 0 and 23 @1"). If None, '
        'the simulation will be annual.', default=''
    )

    air_speed = Inputs.file(
        description='A CSV file containing a single number for air speed in m/s or '
        'several rows of air speeds that align with the length of the run period.',
        optional=True
    )

    met_rate = Inputs.file(
        description='A CSV file containing a single number for metabolic rate in met '
        'or several rows of met values that align with the length of the run period.',
        optional=True
    )

    clo_value = Inputs.file(
        description='A CSV file containing a single number for clothing level in clo '
        'or several rows of clo values that align with the length of the run period.',
        optional=True
    )

    solarcal_parameters = 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'
    )

    comfort_parameters = Inputs.str(
        description='An PMVParameter string to customize the assumptions of '
        'the PMV comfort model.', default='--ppd-threshold 10'
    )

    write_set_map = Inputs.str(
        description='A switch to note whether the output temperature CSV should '
        'record Operative Temperature or Standard Effective Temperature (SET).',
        default='write-op-map'
    )

    @task(template=LongwaveMrtMap)
    def create_longwave_mrt_map(
        self,
        result_sql=result_sql,
        view_factors=view_factors,
        modifiers=modifiers,
        enclosure_info=enclosure_info,
        epw=epw,
        run_period=run_period,
        name=grid_name
    ) -> List[Dict]:
        return [
            {
                'from': LongwaveMrtMap()._outputs.longwave_mrt_map,
                'to': 'conditions/longwave_mrt/{{self.name}}.csv'
            }
        ]

    @task(template=ShortwaveMrtMap)
    def create_shortwave_mrt_map(
        self,
        epw=epw,
        indirect_irradiance=indirect_irradiance,
        direct_irradiance=direct_irradiance,
        ref_irradiance=ref_irradiance,
        sun_up_hours=sun_up_hours,
        contributions=contributions,
        transmittance_contribs=transmittance_contribs,
        trans_schedules=trans_schedules,
        solarcal_par=solarcal_parameters,
        run_period=run_period,
        name=grid_name
    ) -> List[Dict]:
        return [
            {
                'from': ShortwaveMrtMap()._outputs.shortwave_mrt_map,
                'to': 'conditions/shortwave_mrt/{{self.name}}.csv'
            }
        ]

    @task(template=AirMap)
    def create_air_temperature_map(
        self,
        result_sql=result_sql,
        enclosure_info=enclosure_info,
        epw=epw,
        run_period=run_period,
        metric='air-temperature',
        name=grid_name
    ) -> List[Dict]:
        return [
            {
                'from': AirMap()._outputs.air_map,
                'to': 'conditions/air_temperature/{{self.name}}.csv'
            }
        ]

    @task(template=AirMap)
    def create_rel_humidity_map(
        self,
        result_sql=result_sql,
        enclosure_info=enclosure_info,
        epw=epw,
        run_period=run_period,
        metric='relative-humidity',
        name=grid_name
    ) -> List[Dict]:
        return [
            {
                'from': AirMap()._outputs.air_map,
                'to': 'conditions/rel_humidity/{{self.name}}.csv'
            }
        ]

    @task(template=AirSpeedJson)
    def create_air_speed_json(
        self, epw=epw, enclosure_info=enclosure_info, multiply_by=0.5,
        indoor_air_speed=air_speed, run_period=run_period, name=grid_name
    ) -> List[Dict]:
        return [
            {
                'from': AirSpeedJson()._outputs.air_speeds,
                'to': 'conditions/air_speed/{{self.name}}.json'
            }
        ]

    @task(
        template=PmvMtx,
        needs=[
            create_longwave_mrt_map, create_shortwave_mrt_map,
            create_air_temperature_map, create_rel_humidity_map, create_air_speed_json
        ]
    )
    def process_pmv_matrix(
        self,
        air_temperature_mtx=create_air_temperature_map._outputs.air_map,
        rel_humidity_mtx=create_rel_humidity_map._outputs.air_map,
        rad_temperature_mtx=create_longwave_mrt_map._outputs.longwave_mrt_map,
        rad_delta_mtx=create_shortwave_mrt_map._outputs.shortwave_mrt_map,
        air_speed_json=create_air_speed_json._outputs.air_speeds,
        met_rate=met_rate,
        clo_value=clo_value,
        comfort_par=comfort_parameters,
        write_set_map=write_set_map,
        name=grid_name
    ) -> List[Dict]:
        return [
            {
                'from': PmvMtx()._outputs.temperature_map,
                'to': 'results/temperature/{{self.name}}.csv'
            },
            {
                'from': PmvMtx()._outputs.condition_map,
                'to': 'results/condition/{{self.name}}.csv'
            },
            {
                'from': PmvMtx()._outputs.pmv_map,
                'to': 'results/condition_intensity/{{self.name}}.csv'
            }
        ]

    @task(
        template=Tcp,
        needs=[process_pmv_matrix]
    )
    def compute_tcp(
        self,
        condition_csv=process_pmv_matrix._outputs.condition_map,
        enclosure_info=enclosure_info,
        occ_schedule_json=occ_schedules,
        name=grid_name
    ) -> List[Dict]:
        return [
            {'from': Tcp()._outputs.tcp, 'to': 'metrics/TCP/{{self.name}}.csv'},
            {'from': Tcp()._outputs.hsp, 'to': 'metrics/HSP/{{self.name}}.csv'},
            {'from': Tcp()._outputs.csp, 'to': 'metrics/CSP/{{self.name}}.csv'}
        ]
예제 #14
0
class PointInTimeGridEntryPoint(DAG):
    """Point-in-time grid-based entry point."""

    # inputs
    model = Inputs.file(
        description='A Honeybee model in HBJSON file format.',
        extensions=['json', 'hbjson'],
        alias=hbjson_model_input
    )

    sky = Inputs.str(
        description='Sky string for any type of sky (cie, climate-based, irradiance, '
        'illuminance). This can be a minimal representation of the sky through '
        'altitude and azimuth (eg. "cie -alt 71.6 -az 185.2 -type 0"). Or it can be '
        'a detailed specification of time and location (eg. "climate-based 21 Jun 12:00 '
        '-lat 41.78 -lon -87.75 -tz 5 -dni 800 -dhi 120"). Both the altitude and '
        'azimuth must be specified for the minimal representation to be used. See the '
        'honeybee-radiance sky CLI group for a full list of options '
        '(https://www.ladybug.tools/honeybee-radiance/docs/cli/sky.html).'
    )

    metric = Inputs.str(
        description='Text for the type of metric to be output from the calculation. '
        'Choose from: illuminance, irradiance, luminance, radiance.',
        default='illuminance', alias=point_in_time_metric_input,
        spec={'type': 'string',
              'enum': ['illuminance', 'irradiance', 'luminance', 'radiance']},
    )

    grid_filter = Inputs.str(
        description='Text for a grid identifer or a pattern to filter the sensor grids '
        'of the model that are simulated. For instance, first_floor_* will simulate '
        'only the sensor grids that have an identifier that starts with '
        'first_floor_. By default, all grids in the model will be simulated.',
        default='*',
        alias=grid_filter_input
    )

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution',
        spec={'type': 'integer', 'minimum': 1},
        alias=sensor_count_input
    )

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing',
        default='-ab 2 -aa 0.1 -ad 2048 -ar 64',
        alias=rad_par_daylight_factor_input
    )

    @task(template=GenSky)
    def generate_sky(self, sky_string=sky):
        return [
            {
                'from': GenSky()._outputs.sky,
                'to': 'resources/weather.sky'
            }
        ]

    @task(
        template=AdjustSkyForMetric,
        needs=[generate_sky]
    )
    def adjust_sky(self, sky=generate_sky._outputs.sky, metric=metric):
        return [
            {
                'from': AdjustSkyForMetric()._outputs.adjusted_sky,
                'to': 'resources/weather.sky'
            }
        ]

    @task(template=CreateRadianceFolderGrid)
    def create_rad_folder(
        self, input_model=model, grid_filter=grid_filter
            ):
        """Translate the input model to a radiance folder."""
        return [
            {
                'from': CreateRadianceFolderGrid()._outputs.model_folder,
                'to': 'model'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.bsdf_folder,
                'to': 'model/bsdf'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.model_sensor_grids_file,
                'to': 'results/grids_info.json'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
                'description': 'Sensor grids information.'
            }
        ]

    @task(
        template=CreateOctreeWithSky, needs=[adjust_sky, create_rad_folder]
    )
    def create_octree(
        self, model=create_rad_folder._outputs.model_folder,
        sky=adjust_sky._outputs.adjusted_sky
    ):
        """Create octree from radiance folder and sky."""
        return [
            {
                'from': CreateOctreeWithSky()._outputs.scene_file,
                'to': 'resources/scene.oct'
            }
        ]

    @task(
        template=PointInTimeGridRayTracing,
        needs=[create_rad_folder, create_octree],
        loop=create_rad_folder._outputs.sensor_grids,
        sub_folder='initial_results/{{item.name}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid': 'grid/{{item.full_id}}.pts'}  # subpath for sensor_grid
    )
    def point_in_time_grid_ray_tracing(
        self,
        sensor_count=sensor_count,
        radiance_parameters=radiance_parameters,
        metric=metric,
        octree_file=create_octree._outputs.scene_file,
        grid_name='{{item.full_id}}',
        sensor_grid=create_rad_folder._outputs.model_folder,
        bsdfs=create_rad_folder._outputs.bsdf_folder
    ):
        # this task doesn't return a file for each loop.
        # instead we access the results folder directly as an output
        pass

    results = Outputs.folder(
        source='results', description='Folder with raw result files (.res) that contain '
        'numerical values for each sensor. Values are in standard SI units of the input '
        'metric (lux, W/m2, cd/m2, W/m2-sr).', alias=point_in_time_grid_results
    )
예제 #15
0
class AnnualEnergyUseEntryPoint(DAG):
    """Annual energy use entry point."""

    # inputs
    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'],
                        alias=hbjson_model_input)

    epw = Inputs.file(
        description=
        'EPW weather file to be used for the annual energy simulation.',
        extensions=['epw'])

    ddy = Inputs.file(
        description='A DDY file with design days to be used for the initial '
        'sizing calculation.',
        extensions=['ddy'],
        alias=ddy_input)

    filter_des_days = Inputs.str(
        description=
        'A switch for whether the ddy-file should be filtered to only '
        'include 99.6 and 0.4 design days',
        default='filter-des-days',
        spec={
            'type': 'string',
            'enum': ['filter-des-days', 'all-des-days']
        },
        alias=filter_des_days_input)

    units = Inputs.str(
        description=
        'A switch to indicate whether the data in the final EUI file '
        'should be in SI (kWh/m2) or IP (kBtu/ft2). Valid values are "si" and "ip".',
        default='si',
        spec={
            'type': 'string',
            'enum': ['si', 'ip']
        })

    # tasks
    @task(template=SimParDefault)
    def create_sim_par(self,
                       ddy=ddy,
                       filter_des_days=filter_des_days) -> List[Dict]:
        return [{
            'from': SimParDefault()._outputs.sim_par_json,
            'to': 'simulation_parameter.json'
        }]

    @task(template=SimulateModel, needs=[create_sim_par])
    def run_simulation(
            self,
            model=model,
            epw=epw,
            sim_par=create_sim_par._outputs.sim_par_json) -> List[Dict]:
        return [{
            'from': SimulateModel()._outputs.hbjson,
            'to': 'model.hbjson'
        }, {
            'from': SimulateModel()._outputs.result_folder,
            'to': 'run'
        }]

    @task(template=EnergyUseIntensity, needs=[run_simulation])
    def compute_eui(self,
                    result_folder=run_simulation._outputs.result_folder,
                    units=units) -> List[Dict]:
        return [{
            'from': EnergyUseIntensity()._outputs.eui_json,
            'to': 'eui.json'
        }]

    # outputs
    eui = Outputs.file(
        source='eui.json',
        description='A JSON containing energy use intensity '
        'information across the total model floor area. Values are either kWh/m2 '
        'or kBtu/ft2 depending upon the units input.',
        alias=parse_eui_results)

    sql = Outputs.file(
        source='run/eplusout.sql',
        description='The result SQL file output by the simulation.')

    zsz = Outputs.file(source='run/epluszsz.csv',
                       description='The result CSV with the zone loads '
                       'over the design day output by the simulation.',
                       optional=True)

    html = Outputs.file(
        source='run/eplustbl.htm',
        description=
        'The result HTML page with summary reports output by the simulation.')

    err = Outputs.file(
        source='run/eplusout.err',
        description='The error report output by the simulation.')
예제 #16
0
class DirectSunHoursEntryPoint(DAG):
    """Direct sun hours entry point."""

    # inputs
    timestep = Inputs.int(
        description='Input wea timestep. This value will be used to divide the '
        'cumulative results to ensure the units of the output are in hours.',
        default=1,
        spec={
            'type': 'integer',
            'minimum': 1,
            'maximum': 60
        })

    north = Inputs.float(default=0,
                         description='A number for rotation from north.',
                         spec={
                             'type': 'number',
                             'minimum': 0,
                             'maximum': 360
                         },
                         alias=north_input)

    cpu_count = Inputs.int(
        default=50,
        description=
        'The maximum number of CPUs for parallel execution. This will be '
        'used to determine the number of sensors run by each worker.',
        spec={
            'type': 'integer',
            'minimum': 1
        },
        alias=cpu_count)

    min_sensor_count = Inputs.int(
        description='The minimum number of sensors in each sensor grid after '
        'redistributing the sensors based on cpu_count. This value takes '
        'precedence over the cpu_count and can be used to ensure that '
        'the parallelization does not result in generating unnecessarily small '
        'sensor grids. The default value is set to 1, which means that the '
        'cpu_count is always respected.',
        default=1,
        spec={
            'type': 'integer',
            'minimum': 1
        },
        alias=min_sensor_count_input)

    grid_filter = Inputs.str(
        description=
        'Text for a grid identifier or a pattern to filter the sensor grids '
        'of the model that are simulated. For instance, first_floor_* will simulate '
        'only the sensor grids that have an identifier that starts with '
        'first_floor_. By default, all grids in the model will be simulated.',
        default='*',
        alias=grid_filter_input)

    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'],
                        alias=hbjson_model_grid_input)

    wea = Inputs.file(description='Wea file.',
                      extensions=['wea'],
                      alias=wea_input)

    @task(template=WeaToConstant)
    def convert_wea_to_constant(self, wea=wea):
        """Convert a wea to have constant irradiance values."""
        return [{
            'from': WeaToConstant()._outputs.constant_wea,
            'to': 'resources/constant.wea'
        }]

    @task(template=CreateSunMatrix, needs=[convert_wea_to_constant])
    def generate_sunpath(self,
                         wea=convert_wea_to_constant._outputs.constant_wea,
                         north=north,
                         output_type=1):
        """Create sunpath for sun-up-hours."""
        return [{
            'from': CreateSunMatrix()._outputs.sunpath,
            'to': 'resources/sunpath.mtx'
        }, {
            'from': CreateSunMatrix()._outputs.sun_modifiers,
            'to': 'resources/suns.mod'
        }]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(
            self, sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        return [{
            'from': ParseSunUpHours()._outputs.sun_up_hours,
            'to': 'results/direct_sun_hours/sun-up-hours.txt'
        }]

    @task(template=WriteInt)
    def write_timestep(self, src=timestep):
        return [{
            'from': WriteInt()._outputs.dst,
            'to': 'results/direct_sun_hours/timestep.txt'
        }]

    @task(template=CreateRadianceFolderGrid)
    def create_rad_folder(self, input_model=model, grid_filter=grid_filter):
        """Translate the input model to a radiance folder."""
        return [{
            'from': CreateRadianceFolderGrid()._outputs.model_folder,
            'to': 'model'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.bsdf_folder,
            'to': 'model/bsdf'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids_file,
            'to': 'results/direct_sun_hours/grids_info.json'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(template=Copy, needs=[create_rad_folder])
    def copy_grid_info(self, src=create_rad_folder._outputs.sensor_grids_file):
        return [{
            'from': Copy()._outputs.dst,
            'to': 'results/cumulative/grids_info.json'
        }]

    @task(template=CreateOctreeWithSky,
          needs=[generate_sunpath, create_rad_folder])
    def create_octree(self,
                      model=create_rad_folder._outputs.model_folder,
                      sky=generate_sunpath._outputs.sunpath):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [{
            'from': CreateOctreeWithSky()._outputs.scene_file,
            'to': 'resources/scene_with_suns.oct'
        }]

    @task(template=SplitGridFolder,
          needs=[create_rad_folder],
          sub_paths={'input_folder': 'grid'})
    def split_grid_folder(self,
                          input_folder=create_rad_folder._outputs.model_folder,
                          cpu_count=cpu_count,
                          cpus_per_grid=1,
                          min_sensor_count=min_sensor_count):
        """Split sensor grid folder based on the number of CPUs"""
        return [{
            'from': SplitGridFolder()._outputs.output_folder,
            'to': 'resources/grid'
        }, {
            'from': SplitGridFolder()._outputs.dist_info,
            'to': 'initial_results/direct_sun_hours/_redist_info.json'
        }, {
            'from': SplitGridFolder()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(template=Copy, needs=[split_grid_folder])
    def copy_redist_info(self, src=split_grid_folder._outputs.dist_info):
        return [{
            'from': Copy()._outputs.dst,
            'to': 'initial_results/cumulative/_redist_info.json'
        }]

    @task(
        template=DirectSunHoursCalculation,
        needs=[
            create_octree, generate_sunpath, create_rad_folder,
            split_grid_folder
        ],
        loop=split_grid_folder._outputs.sensor_grids,
        sub_folder=
        'initial_results/{{item.full_id}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid':
                   '{{item.full_id}}.pts'}  # sensor_grid sub_path
    )
    def direct_sun_hours_raytracing(
            self,
            timestep=timestep,
            sensor_count='{{item.count}}',
            octree_file=create_octree._outputs.scene_file,
            grid_name='{{item.full_id}}',
            sensor_grid=split_grid_folder._outputs.output_folder,
            sunpath=generate_sunpath._outputs.sunpath,
            sun_modifiers=generate_sunpath._outputs.sun_modifiers,
            bsdfs=create_rad_folder._outputs.bsdf_folder):
        pass

    @task(template=MergeFolderData, needs=[direct_sun_hours_raytracing])
    def restructure_timestep_results(
            self,
            input_folder='initial_results/direct_sun_hours',
            extension='ill'):
        return [{
            'from': MergeFolderData()._outputs.output_folder,
            'to': 'results/direct_sun_hours'
        }]

    @task(template=MergeFolderData, needs=[direct_sun_hours_raytracing])
    def restructure_cumulative_results(
            self, input_folder='initial_results/cumulative', extension='res'):
        return [{
            'from': MergeFolderData()._outputs.output_folder,
            'to': 'results/cumulative'
        }]

    direct_sun_hours = Outputs.folder(
        source='results/direct_sun_hours',
        description='Hourly results for direct sun hours.',
        alias=direct_sun_hours_results)

    cumulative_sun_hours = Outputs.folder(
        source='results/cumulative',
        description='Cumulative direct sun hours for all the input hours.',
        alias=cumulative_sun_hour_results)
예제 #17
0
class DirectSunHoursEntryPoint(DAG):
    """Direct sun hours entry point."""

    # inputs
    north = Inputs.float(default=0,
                         description='A number for rotation from north.',
                         spec={
                             'type': 'number',
                             'minimum': 0,
                             'maximum': 360
                         },
                         alias=north_input)

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution.',
        spec={
            'type': 'integer',
            'minimum': 1
        },
        alias=sensor_count_input)

    grid_filter = Inputs.str(
        description=
        'Text for a grid identifer or a pattern to filter the sensor grids '
        'of the model that are simulated. For instance, first_floor_* will simulate '
        'only the sensor grids that have an identifier that starts with '
        'first_floor_. By default, all grids in the model will be simulated.',
        default='*',
        alias=grid_filter_input)

    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'],
                        alias=hbjson_model_input)

    wea = Inputs.file(description='Wea file.',
                      extensions=['wea'],
                      alias=wea_input)

    @task(template=WeaToConstant)
    def convert_wea_to_constant(self, wea=wea):
        """Convert a wea to have constant irradiance values."""
        return [{
            'from': WeaToConstant()._outputs.constant_wea,
            'to': 'resources/constant.wea'
        }]

    @task(template=CreateSunMatrix, needs=[convert_wea_to_constant])
    def generate_sunpath(self,
                         wea=convert_wea_to_constant._outputs.constant_wea,
                         north=north,
                         output_type=1):
        """Create sunpath for sun-up-hours."""
        return [{
            'from': CreateSunMatrix()._outputs.sunpath,
            'to': 'resources/sunpath.mtx'
        }, {
            'from': CreateSunMatrix()._outputs.sun_modifiers,
            'to': 'resources/suns.mod'
        }]

    @task(template=CreateRadianceFolderGrid)
    def create_rad_folder(self, input_model=model, grid_filter=grid_filter):
        """Translate the input model to a radiance folder."""
        return [{
            'from': CreateRadianceFolderGrid()._outputs.model_folder,
            'to': 'model'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids_file,
            'to': 'results/direct_sun_hours/grids_info.json'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(template=CopyMultiple, needs=[create_rad_folder])
    def copy_grid_info(self, src=create_rad_folder._outputs.sensor_grids_file):
        return [{
            'from': CopyMultiple()._outputs.dst_1,
            'to': 'results/cumulative/grids_info.json'
        }, {
            'from': CopyMultiple()._outputs.dst_2,
            'to': 'results/direct_radiation/grids_info.json'
        }]

    @task(template=CreateOctreeWithSky,
          needs=[generate_sunpath, create_rad_folder])
    def create_octree(self,
                      model=create_rad_folder._outputs.model_folder,
                      sky=generate_sunpath._outputs.sunpath):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [{
            'from': CreateOctreeWithSky()._outputs.scene_file,
            'to': 'resources/scene_with_suns.oct'
        }]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(
            self, sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        return [{
            'from': ParseSunUpHours()._outputs.sun_up_hours,
            'to': 'results/direct_sun_hours/sun-up-hours.txt'
        }]

    @task(
        template=DirectSunHoursEntryLoop,
        needs=[create_octree, generate_sunpath, create_rad_folder],
        loop=create_rad_folder._outputs.sensor_grids,
        sub_folder=
        'initial_results/{{item.name}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid':
                   'grid/{{item.full_id}}.pts'}  # sub_path for sensor_grid arg
    )
    def direct_sun_hours_raytracing(
            self,
            sensor_count=sensor_count,
            octree_file=create_octree._outputs.scene_file,
            grid_name='{{item.full_id}}',
            sensor_grid=create_rad_folder._outputs.model_folder,
            sunpath=generate_sunpath._outputs.sunpath,
            sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        pass

    direct_sun_hours = Outputs.folder(
        source='results/direct_sun_hours',
        description='Hourly results for direct sun hours.',
        alias=direct_sun_hours_results)

    cumulative_sun_hours = Outputs.folder(
        source='results/cumulative',
        description=
        'Cumulative results for direct sun hours for all the input hours.',
        alias=cumulative_sun_hour_results)
예제 #18
0
class DirectSunHoursEntryPoint(DAG):
    """Direct sun hours entry point."""

    # inputs
    north = Inputs.float(default=0,
                         description='A number for rotation from north.',
                         spec={
                             'type': 'number',
                             'minimum': 0,
                             'maximum': 360
                         },
                         alias=north_input)

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution.',
        spec={
            'type': 'integer',
            'minimum': 1
        })

    sensor_grid = Inputs.str(
        description=
        'A grid name or a pattern to filter the sensor grids. By default '
        'all the grids in HBJSON model will be exported.',
        default='*')

    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'],
                        alias=hbjson_model_input)

    wea = Inputs.file(description='Wea file.',
                      extensions=['wea'],
                      alias=wea_input)

    @task(template=CreateSunMatrix)
    def generate_sunpath(self, north=north, wea=wea, output_type=1):
        """Create sunpath for sun-up-hours."""
        return [{
            'from': CreateSunMatrix()._outputs.sunpath,
            'to': 'resources/sunpath.mtx'
        }, {
            'from': CreateSunMatrix()._outputs.sun_modifiers,
            'to': 'resources/suns.mod'
        }]

    @task(template=CreateRadianceFolder)
    def create_rad_folder(self, input_model=model, sensor_grid=sensor_grid):
        """Translate the input model to a radiance folder."""
        return [{
            'from': CreateRadianceFolder()._outputs.model_folder,
            'to': 'model'
        }, {
            'from': CreateRadianceFolder()._outputs.sensor_grids_file,
            'to': 'results/direct_sun_hours/grids_info.json'
        }, {
            'from': CreateRadianceFolder()._outputs.sensor_grids_file,
            'to': 'results/cumulative/grids_info.json'
        }, {
            'from': CreateRadianceFolder()._outputs.sensor_grids_file,
            'to': 'results/direct_radiation/grids_info.json'
        }, {
            'from': CreateRadianceFolder()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(template=CreateOctreeWithSky,
          needs=[generate_sunpath, create_rad_folder])
    def create_octree(self,
                      model=create_rad_folder._outputs.model_folder,
                      sky=generate_sunpath._outputs.sunpath):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [{
            'from': CreateOctreeWithSky()._outputs.scene_file,
            'to': 'resources/scene_with_suns.oct'
        }]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(
            self, sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        return [{
            'from': ParseSunUpHours()._outputs.sun_up_hours,
            'to': 'results/direct_sun_hours/sun-up-hours.txt'
        }]

    @task(
        template=DirectSunHoursEntryLoop,
        needs=[create_octree, generate_sunpath, create_rad_folder],
        loop=create_rad_folder._outputs.sensor_grids,
        sub_folder=
        'initial_results/{{item.name}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid':
                   'grid/{{item.full_id}}.pts'}  # sub_path for sensor_grid arg
    )
    def direct_sun_hours_raytracing(
            self,
            sensor_count=sensor_count,
            octree_file=create_octree._outputs.scene_file,
            grid_name='{{item.full_id}}',
            sensor_grid=create_rad_folder._outputs.model_folder,
            sunpath=generate_sunpath._outputs.sunpath,
            sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        pass

    results = Outputs.folder(
        source='results',
        description=
        'Results folder. There are 3 subfolders under results folder: '
        'direct_sun_hours, cumulative and direct_radiation.')

    direct_sun_hours = Outputs.folder(
        source='results/direct_sun_hours',
        description='Hourly results for direct sun hours.',
        # alias=sort_direct_results/direct_sun_hours
    )

    cumulative_sun_hours = Outputs.folder(
        source='results/cumulative',
        description=
        'Cumulative results for direct sun hours for all the input hours.',
        # alias=sort_direct_results/direct_sun_hours
    )

    direct_radiation = Outputs.folder(
        source='results/direct_radiation',
        description=
        'Hourly direct radiation results. These results only includes the '
        'direct radiation from sun disk.',
        # alias=sort_direct_results/direct_sun_hours
    )
예제 #19
0
class AnnualRadiationEntryPoint(DAG):
    """Annual radiation entry point."""

    # inputs
    north = Inputs.float(default=0,
                         description='A number for rotation from north.',
                         spec={
                             'type': 'number',
                             'minimum': -360,
                             'maximum': 360
                         },
                         alias=north_input)

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution.',
        spec={
            'type': 'integer',
            'minimum': 1
        },
        alias=sensor_count_input)

    radiance_parameters = Inputs.str(
        description='Radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05',
        alias=rad_par_annual_input)

    grid_filter = Inputs.str(
        description=
        'Text for a grid identifer or a pattern to filter the sensor grids '
        'of the model that are simulated. For instance, first_floor_* will simulate '
        'only the sensor grids that have an identifier that starts with '
        'first_floor_. By default, all grids in the model will be simulated.',
        default='*',
        alias=grid_filter_input)

    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'],
                        alias=hbjson_model_input)

    wea = Inputs.file(description='Wea file.',
                      extensions=['wea'],
                      alias=wea_input)

    @task(template=CreateSunMatrix)
    def generate_sunpath(self, north=north, wea=wea, output_type=1):
        """Create sunpath for sun-up-hours."""
        return [{
            'from': CreateSunMatrix()._outputs.sunpath,
            'to': 'resources/sunpath.mtx'
        }, {
            'from': CreateSunMatrix()._outputs.sun_modifiers,
            'to': 'resources/suns.mod'
        }]

    @task(template=CreateRadianceFolderGrid)
    def create_rad_folder(self, input_model=model, grid_filter=grid_filter):
        """Translate the input model to a radiance folder."""
        return [{
            'from': CreateRadianceFolderGrid()._outputs.model_folder,
            'to': 'model'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids_file,
            'to': 'results/direct/grids_info.json'
        }, {
            'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
            'description': 'Sensor grids information.'
        }]

    @task(template=Copy, needs=[create_rad_folder])
    def copy_grid_info(self, src=create_rad_folder._outputs.sensor_grids_file):
        return [{
            'from': Copy()._outputs.dst,
            'to': 'results/total/grids_info.json'
        }]

    @task(template=CreateOctree, needs=[create_rad_folder])
    def create_octree(self, model=create_rad_folder._outputs.model_folder):
        """Create octree from radiance folder."""
        return [{
            'from': CreateOctreeWithSky()._outputs.scene_file,
            'to': 'resources/scene.oct'
        }]

    @task(template=CreateOctreeWithSky,
          needs=[generate_sunpath, create_rad_folder])
    def create_octree_with_suns(self,
                                model=create_rad_folder._outputs.model_folder,
                                sky=generate_sunpath._outputs.sunpath):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [{
            'from': CreateOctreeWithSky()._outputs.scene_file,
            'to': 'resources/scene_with_suns.oct'
        }]

    @task(template=CreateSkyDome)
    def create_sky_dome(self):
        """Create sky dome for daylight coefficient studies."""
        return [{
            'from': CreateSkyDome()._outputs.sky_dome,
            'to': 'resources/sky.dome'
        }]

    @task(template=CreateSkyMatrix)
    def create_indirect_sky(self,
                            north=north,
                            wea=wea,
                            sky_type='no-sun',
                            output_type='solar',
                            output_format='ASCII',
                            sun_up_hours='sun-up-hours'):
        return [{
            'from': CreateSkyMatrix()._outputs.sky_matrix,
            'to': 'resources/sky_direct.mtx'
        }]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(
            self, sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        return [{
            'from': ParseSunUpHours()._outputs.sun_up_hours,
            'to': 'results/total/sun-up-hours.txt'
        }]

    @task(template=Copy, needs=[parse_sun_up_hours])
    def copy_sun_up_hours(self, src=parse_sun_up_hours._outputs.sun_up_hours):
        return [{
            'from': Copy()._outputs.dst,
            'to': 'results/direct/sun-up-hours.txt'
        }]

    @task(
        template=AnnualRadiationRayTracing,
        needs=[
            create_sky_dome, create_octree_with_suns, create_octree,
            generate_sunpath, create_indirect_sky, create_rad_folder
        ],
        loop=create_rad_folder._outputs.sensor_grids,
        sub_folder=
        'initial_results/{{item.name}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid':
                   'grid/{{item.full_id}}.pts'}  # sub_path for sensor_grid arg
    )
    def annual_radiation_raytracing(
            self,
            sensor_count=sensor_count,
            radiance_parameters=radiance_parameters,
            octree_file_with_suns=create_octree_with_suns._outputs.scene_file,
            octree_file=create_octree._outputs.scene_file,
            grid_name='{{item.full_id}}',
            sensor_grid=create_rad_folder._outputs.model_folder,
            sky_dome=create_sky_dome._outputs.sky_dome,
            sky_matrix_indirect=create_indirect_sky._outputs.sky_matrix,
            sunpath=generate_sunpath._outputs.sunpath,
            sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        pass

    total_radiation = Outputs.folder(
        source='results/total',
        description='Folder with raw result files (.ill) that '
        'contain matrices of total irradiance.',
        alias=total_radiation_results)

    direct_radiation = Outputs.folder(
        source='results/direct',
        description='Folder with raw result files (.ill) that '
        'contain matrices of direct irradiance.',
        alias=direct_radiation_results)
예제 #20
0
class DynamicShadeContribEntryPoint(DAG):
    """Entry point for computing the contributions from dynamic windows."""

    # inputs
    radiance_parameters = Inputs.str(
        description='Radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05',
    )

    octree_file = Inputs.file(
        description=
        'A Radiance octree file with a completely transparent version '
        'of the dynamic shade group.',
        extensions=['oct'])

    octree_file_with_suns = Inputs.file(
        description='A Radiance octree file with sun modifiers.',
        extensions=['oct'])

    group_name = Inputs.str(
        description='Name for the dynamic aperture group being simulated.')

    sensor_grid_folder = Inputs.folder(
        description=
        'A folder containing all of the split sensor grids in the model.')

    sensor_grids = Inputs.file(
        description=
        'A JSON file with information about sensor grids to loop over.')

    sky_dome = Inputs.file(description='Path to sky dome file.')

    sky_matrix = Inputs.file(description='Path to total sky matrix file.')

    sky_matrix_direct = Inputs.file(
        description='Path to direct skymtx file (gendaymtx -d).')

    sun_modifiers = Inputs.file(description='A file with sun modifiers.')

    sun_up_hours = Inputs.file(
        description=
        'A sun-up-hours.txt file output by Radiance and aligns with the '
        'input irradiance files.')

    @task(template=ReadJSONList)
    def read_grids_for_shade(self, src=sensor_grids) -> List[Dict]:
        return [{
            'from': ReadJSONList()._outputs.data,
            'description': 'Sensor grids information.'
        }]

    @task(template=ShadeContribEntryPoint,
          needs=[read_grids_for_shade],
          loop=read_grids_for_shade._outputs.data,
          sub_folder='shortwave',
          sub_paths={
              'sensor_grid': '{{item.full_id}}.pts',
              'ref_sensor_grid': '{{item.full_id}}_ref.pts',
          })
    def run_radiance_shade_contrib(self,
                                   radiance_parameters=radiance_parameters,
                                   octree_file=octree_file,
                                   octree_file_with_suns=octree_file_with_suns,
                                   group_name=group_name,
                                   grid_name='{{item.full_id}}',
                                   sensor_grid=sensor_grid_folder,
                                   ref_sensor_grid=sensor_grid_folder,
                                   sensor_count='{{item.count}}',
                                   sky_dome=sky_dome,
                                   sky_matrix=sky_matrix,
                                   sky_matrix_direct=sky_matrix_direct,
                                   sun_modifiers=sun_modifiers,
                                   sun_up_hours=sun_up_hours) -> List[Dict]:
        pass
예제 #21
0
class GeojsonAnnualEnergyUseEntryPoint(DAG):
    """GeoJSON annual energy use entry point."""

    # inputs
    geojson = Inputs.file(
        description='A geoJSON file with building footprints as Polygons or '
        'MultiPolygons.',
        path='model.geojson',
        extensions=['geojson', 'json'])

    epw = Inputs.file(
        description=
        'EPW weather file to be used for the annual energy simulation.',
        extensions=['epw'])

    ddy = Inputs.file(
        description='A DDY file with design days to be used for the initial '
        'sizing calculation.',
        extensions=['ddy'],
        alias=ddy_input)

    window_ratio = Inputs.str(
        description=
        'A number between 0 and 1 (but not perfectly equal to 1) for the '
        'desired ratio between window area and wall area. If multiple values are '
        'input here (each separated by a space), different WindowParameters will be '
        'assigned based on cardinal direction, starting with north and moving '
        'clockwise.',
        default='0.4')

    all_to_buildings = Inputs.str(
        description=
        'A switch to indicate if all geometries in the geojson file should '
        'be considered buildings. If buildings-only, this method will only generate '
        'footprints from geometries that are defined as a "Building" in the type '
        'field of its corresponding properties.',
        default='buildings-only',
        spec={
            'type': 'string',
            'enum': ['buildings-only', 'all-to-buildings']
        })

    existing_to_context = Inputs.str(
        description=
        'A switch to indicate whether polygons possessing a building_status '
        'of "Existing" under their properties should be imported as ContextShade '
        'instead of Building objects.',
        default='existing-to-context',
        spec={
            'type': 'string',
            'enum': ['no-context', 'existing-to-context']
        })

    separate_top_bottom = Inputs.str(
        description=
        'A switch to indicate whether top/bottom stories of the buildings '
        'should not be separated in order to account for different boundary conditions '
        'of the roof and ground floor.',
        default='separate-top-bottom',
        spec={
            'type': 'string',
            'enum': ['separate-top-bottom', 'no-separation']
        })

    use_multiplier = Inputs.str(
        description=
        'A switch to note whether the multipliers on each Building story '
        'should be passed along to the generated Honeybee Room objects or if full '
        'geometry objects should be written for each story of each dragonfly building.',
        default='full-geometry',
        spec={
            'type': 'string',
            'enum': ['full-geometry', 'multiplier']
        },
        alias=use_multiplier_input)

    shade_dist = Inputs.str(
        description=
        'A number to note the distance beyond which other buildings shade '
        'should be excluded from a given Honeybee Model. This can include the units of '
        'the distance (eg. 100ft) or, if no units are provided, the value will be '
        'interpreted in the dragonfly model units. If 0, shade from all neighboring '
        'buildings will be excluded from the resulting models.',
        default='50m')

    filter_des_days = Inputs.str(
        description=
        'A switch for whether the ddy-file should be filtered to only '
        'include 99.6 and 0.4 design days',
        default='filter-des-days',
        spec={
            'type': 'string',
            'enum': ['filter-des-days', 'all-des-days']
        },
        alias=filter_des_days_input)

    units = Inputs.str(
        description=
        'A switch to indicate whether the data in the final EUI file '
        'should be in SI (kWh/m2) or IP (kBtu/ft2). Valid values are "si" and "ip".',
        default='si',
        spec={
            'type': 'string',
            'enum': ['si', 'ip']
        })

    # tasks
    @task(template=ModelFromGeojson)
    def convert_from_geojson(
            self,
            geojson=geojson,
            all_to_buildings=all_to_buildings,
            existing_to_context=existing_to_context,
            separate_top_bottom=separate_top_bottom) -> List[Dict]:
        return [{
            'from': ModelFromGeojson()._outputs.model,
            'to': 'model_init.dfjson'
        }]

    @task(template=WindowsByRatio, needs=[convert_from_geojson])
    def assign_windows(self,
                       model=convert_from_geojson._outputs.model,
                       ratio=window_ratio) -> List[Dict]:
        return [{
            'from': WindowsByRatio()._outputs.new_model,
            'to': 'model.dfjson'
        }]

    @task(template=ModelToHoneybee, needs=[assign_windows])
    def convert_to_honeybee(self,
                            model=assign_windows._outputs.new_model,
                            obj_per_model='Story',
                            use_multiplier=use_multiplier,
                            shade_dist=shade_dist) -> List[Dict]:
        return [{
            'from': ModelToHoneybee()._outputs.output_folder,
            'to': 'models'
        }, {
            'from': ModelToHoneybee()._outputs.hbjson_list,
            'description': 'Information about exported HBJSONs.'
        }]

    @task(template=SimParDefault)
    def create_sim_par(self,
                       ddy=ddy,
                       filter_des_days=filter_des_days) -> List[Dict]:
        return [{
            'from': SimParDefault()._outputs.sim_par_json,
            'to': 'simulation_parameter.json'
        }]

    @task(
        template=SimulateModel,
        needs=[create_sim_par, convert_to_honeybee],
        loop=convert_to_honeybee._outputs.hbjson_list,
        sub_folder='results',  # create a subfolder for results
        sub_paths={'model': '{{item.path}}'}  # sub_path for sim_par arg
    )
    def run_simulation(
            self,
            model=convert_to_honeybee._outputs.output_folder,
            epw=epw,
            sim_par=create_sim_par._outputs.sim_par_json) -> List[Dict]:
        return [{
            'from': SimulateModel()._outputs.sql,
            'to': 'sql/{{item.id}}.sql'
        }, {
            'from': SimulateModel()._outputs.zsz,
            'to': 'zsz/{{item.id}}_zsz.csv'
        }, {
            'from': SimulateModel()._outputs.html,
            'to': 'html/{{item.id}}.htm'
        }, {
            'from': SimulateModel()._outputs.err,
            'to': 'err/{{item.id}}.err'
        }]

    @task(template=EnergyUseIntensity, needs=[run_simulation])
    def compute_eui(self,
                    result_folder='results/sql',
                    units=units) -> List[Dict]:
        return [{
            'from': EnergyUseIntensity()._outputs.eui_json,
            'to': 'eui.json'
        }]

    # outputs
    eui = Outputs.file(
        source='eui.json',
        description='A JSON containing energy use intensity '
        'information across the total model floor area. Values are either kWh/m2 '
        'or kBtu/ft2 depending upon the units input.',
        alias=parse_eui_results)

    dfjson = Outputs.file(source='model.dfjson',
                          description='The DFJSON model used for simulation.')

    hbjson = Outputs.folder(
        source='models',
        description='Folder containing the HBJSON models used for simulation.')

    sql = Outputs.folder(
        source='results/sql',
        description=
        'Folder containing the result SQL files output by the simulation.')

    zsz = Outputs.folder(source='results/zsz',
                         description='Folder containing the CSV files with '
                         'the zone loads over the design day.',
                         optional=True)

    html = Outputs.folder(
        source='results/html',
        description=
        'Folder containing the result HTML pages with summary reports.')

    err = Outputs.folder(
        source='results/err',
        description=
        'Folder containing the error reports output by the simulation.')
예제 #22
0
class RadianceContribEntryPoint(DAG):
    """Entry point for Radiance calculations for comfort mapping."""

    # inputs
    radiance_parameters = Inputs.str(
        description='Radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05',
    )

    octree_file_spec = Inputs.file(
        description='A Radiance octree file with a specular version of the '
        'window group.', extensions=['oct']
    )

    octree_file_diff = Inputs.file(
        description='A Radiance octree file with a diffuse version of the window group.',
        extensions=['oct']
    )

    octree_file_with_suns = Inputs.file(
        description='A Radiance octree file with sun modifiers.',
        extensions=['oct']
    )

    group_name = Inputs.str(
        description='Name for the dynamic aperture group being simulated.'
    )

    grid_name = Inputs.str(
        description='Sensor grid file name (used to name the final result files).'
    )

    sensor_grid = Inputs.file(
        description='Sensor grid file.',
        extensions=['pts']
    )

    ref_sensor_grid = Inputs.file(
        description='Reflected Sensor grid file.',
        extensions=['pts']
    )

    sensor_count = Inputs.int(
        description='Number of sensors in the input sensor grid.'
    )

    sky_dome = Inputs.file(
        description='Path to sky dome file.'
    )

    sky_matrix = Inputs.file(
        description='Path to total sky matrix file.'
    )

    sky_matrix_direct = Inputs.file(
        description='Path to direct skymtx file (gendaymtx -d).'
    )

    sun_modifiers = Inputs.file(
        description='A file with sun modifiers.'
    )

    result_sql = Inputs.file(
        description='A SQLite file that was generated by EnergyPlus and contains '
        'window transmittance results.',
        extensions=['sql', 'db', 'sqlite']
    )

    sun_up_hours = Inputs.file(
        description='A sun-up-hours.txt file output by Radiance and aligns with the '
        'input irradiance files.'
    )

    @task(template=DaylightContribution)
    def direct_sun_group(
        self,
        grid=grid_name,
        group=group_name,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -ab 0 -dc 1.0 -dt 0.0 -dj 0.0 -dr 0',
        sensor_count=sensor_count,
        modifiers=sun_modifiers,
        sensor_grid=sensor_grid,
        conversion='0.265 0.670 0.065',
        output_format='a',  # make it ascii so we expose the file as a separate output
        header='remove',  # remove header to make it process-able later
        scene_file=octree_file_with_suns
    ):
        return [
            {
                'from': DaylightContribution()._outputs.result_file,
                'to': 'dynamic/initial/{{self.group}}/direct_spec/{{self.grid}}.ill'
            }
        ]

    @task(template=DaylightCoefficient)
    def direct_sky_group(
        self,
        grid=grid_name,
        group=group_name,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -ab 1 -c 1 -faf',
        sensor_count=sensor_count,
        sky_matrix=sky_matrix_direct,
        sky_dome=sky_dome,
        sensor_grid=sensor_grid,
        conversion='0.265 0.670 0.065',  # divide by 179
        scene_file=octree_file_spec
    ):
        return [
            {
                'from': DaylightCoefficient()._outputs.result_file,
                'to': 'dynamic/initial/{{self.group}}/direct_sky/{{self.grid}}.ill'
            }
        ]

    @task(template=DaylightCoefficient)
    def total_sky_spec_group(
        self,
        grid=grid_name,
        group=group_name,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -c 1 -faf',
        sensor_count=sensor_count,
        sky_matrix=sky_matrix,
        sky_dome=sky_dome,
        sensor_grid=sensor_grid,
        conversion='0.265 0.670 0.065',  # divide by 179
        scene_file=octree_file_spec
    ):
        return [
            {
                'from': DaylightCoefficient()._outputs.result_file,
                'to': 'dynamic/initial/{{self.group}}/total_sky/{{self.grid}}.ill'
            }
        ]

    @task(template=SubtractSkyMatrix, needs=[total_sky_spec_group, direct_sky_group])
    def output_matrix_math_group(
        self,
        grid=grid_name,
        group=group_name,
        total_sky_matrix=total_sky_spec_group._outputs.result_file,
        direct_sky_matrix=direct_sky_group._outputs.result_file
    ):
        return [
            {
                'from': SubtractSkyMatrix()._outputs.results_file,
                'to': 'dynamic/initial/{{self.group}}/indirect_spec/{{self.grid}}.ill'
            }
        ]

    @task(template=DaylightCoefficient)
    def ground_reflected_sky_spec_group(
        self,
        grid=grid_name,
        group=group_name,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -c 1',
        sensor_count=sensor_count,
        sky_matrix=sky_matrix,
        sky_dome=sky_dome,
        sensor_grid=ref_sensor_grid,
        conversion='0.265 0.670 0.065',  # divide by 179
        output_format='a',  # make it ascii so we expose the file as a separate output
        header='remove',  # remove header to make it process-able later
        scene_file=octree_file_spec
    ):
        return [
            {
                'from': DaylightCoefficient()._outputs.result_file,
                'to': 'dynamic/initial/{{self.group}}/reflected_spec/{{self.grid}}.ill'
            }
        ]

    @task(template=DaylightCoefficient)
    def total_sky_diff_group(
        self,
        grid=grid_name,
        group=group_name,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -c 1',
        sensor_count=sensor_count,
        sky_matrix=sky_matrix,
        sky_dome=sky_dome,
        sensor_grid=sensor_grid,
        conversion='0.265 0.670 0.065',  # divide by 179
        output_format='a',  # make it ascii so we expose the file as a separate output
        header='remove',  # remove header to make it process-able later
        scene_file=octree_file_diff
    ):
        return [
            {
                'from': DaylightCoefficient()._outputs.result_file,
                'to': 'dynamic/initial/{{self.group}}/total_diff/{{self.grid}}.ill'
            }
        ]

    @task(template=DaylightCoefficient)
    def ground_reflected_sky_diff_group(
        self,
        grid=grid_name,
        group=group_name,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -c 1',
        sensor_count=sensor_count,
        sky_matrix=sky_matrix,
        sky_dome=sky_dome,
        sensor_grid=ref_sensor_grid,
        conversion='0.265 0.670 0.065',  # divide by 179
        output_format='a',  # make it ascii so we expose the file as a separate output
        header='remove',  # remove header to make it process-able later
        scene_file=octree_file_diff
    ):
        return [
            {
                'from': DaylightCoefficient()._outputs.result_file,
                'to': 'dynamic/initial/{{self.group}}/reflected_diff/{{self.grid}}.ill'
            }
        ]

    @task(
        template=IrradianceContribMap,
        needs=[
            direct_sun_group, output_matrix_math_group, ground_reflected_sky_spec_group,
            total_sky_diff_group, ground_reflected_sky_diff_group
        ]
    )
    def create_irradiance_contrib_map(
        self,
        result_sql=result_sql,
        direct_specular=direct_sun_group._outputs.result_file,
        indirect_specular=output_matrix_math_group._outputs.results_file,
        ref_specular=ground_reflected_sky_spec_group._outputs.result_file,
        indirect_diffuse=total_sky_diff_group._outputs.result_file,
        ref_diffuse=ground_reflected_sky_diff_group._outputs.result_file,
        sun_up_hours=sun_up_hours,
        aperture_id=group_name,
        grid=grid_name
    ) -> List[Dict]:
        return [
            {
                'from': IrradianceContribMap()._outputs.result_folder,
                'to': 'dynamic/final/{{self.grid}}/{{self.aperture_id}}'
            }
        ]
예제 #23
0
class RadianceMappingEntryPoint(DAG):
    """Entry point for Radiance calculations for comfort mapping."""

    # inputs
    radiance_parameters = Inputs.str(
        description='Radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05',
    )

    model = Inputs.file(description='A Honeybee model in HBJSON file format.',
                        extensions=['json', 'hbjson'])

    octree_file_with_suns = Inputs.file(
        description='A Radiance octree file with sun modifiers.',
        extensions=['oct'])

    octree_file = Inputs.file(
        description='A Radiance octree file with a sky dome.',
        extensions=['oct'])

    octree_file_view_factor = Inputs.file(
        description=
        'A Radiance octree file with surface view factor modifiers.',
        extensions=['oct'])

    grid_name = Inputs.str(
        description=
        'Sensor grid file name (used to name the final result files).')

    sensor_grid = Inputs.file(description='Sensor grid file.',
                              extensions=['pts'])

    sensor_count = Inputs.int(
        description='Number of sensors in the input sensor grid.')

    sky_dome = Inputs.file(description='Path to sky dome file.')

    sky_matrix = Inputs.file(description='Path to total sky matrix file.')

    sky_matrix_direct = Inputs.file(
        description='Path to direct skymtx file (gendaymtx -d).')

    sun_modifiers = Inputs.file(description='A file with sun modifiers.')

    view_factor_modifiers = Inputs.file(
        description='A file with surface modifiers.')

    @task(template=RadiantEnclosureInfo)
    def get_enclosure_info(self,
                           model=model,
                           input_grid=sensor_grid,
                           name=grid_name):
        return [{
            'from': RadiantEnclosureInfo()._outputs.enclosure_file,
            'to': 'enclosures/{{self.name}}.json'
        }]

    @task(template=SphericalViewFactorContribution)
    def compute_spherical_view_factors(
            self,
            name=grid_name,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -ab 1 -c 1 -faf',
            modifiers=view_factor_modifiers,
            sensor_grid=sensor_grid,
            scene_file=octree_file_view_factor):
        return [{
            'from':
            SphericalViewFactorContribution()._outputs.view_factor_file,
            'to': 'longwave/view_factors/{{self.name}}.csv'
        }]

    @task(template=MirrorGrid)
    def mirror_the_grid(self,
                        input_grid=sensor_grid,
                        name=grid_name,
                        vector='0 0 1'):
        return [{
            'from': MirrorGrid()._outputs.base_file,
            'to': 'shortwave/grids/{{self.name}}.pts'
        }, {
            'from': MirrorGrid()._outputs.mirrored_file,
            'to': 'shortwave/grids/{{self.name}}_ref.pts'
        }]

    @task(template=DaylightContribution, needs=[mirror_the_grid])
    def direct_sun(
        self,
        name=grid_name,
        radiance_parameters=radiance_parameters,
        fixed_radiance_parameters='-aa 0.0 -I -ab 0 -dc 1.0 -dt 0.0 -dj 0.0 -dr 0',
        sensor_count=sensor_count,
        modifiers=sun_modifiers,
        sensor_grid=mirror_the_grid._outputs.base_file,
        conversion='0.265 0.670 0.065',
        output_format='a',  # make it ascii so we expose the file as a separate output
        header='remove',  # remove header to make it process-able later
        scene_file=octree_file_with_suns):
        return [{
            'from': DaylightContribution()._outputs.result_file,
            'to': 'shortwave/results/direct/{{self.name}}.ill'
        }]

    @task(template=DaylightCoefficient, needs=[mirror_the_grid])
    def direct_sky(
            self,
            name=grid_name,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -ab 1 -c 1 -faf',
            sensor_count=sensor_count,
            sky_matrix=sky_matrix_direct,
            sky_dome=sky_dome,
            sensor_grid=mirror_the_grid._outputs.base_file,
            conversion='0.265 0.670 0.065',  # divide by 179
            scene_file=octree_file):
        return [{
            'from': DaylightCoefficient()._outputs.result_file,
            'to': 'shortwave/initial_results/direct_sky/{{self.name}}.ill'
        }]

    @task(template=DaylightCoefficient, needs=[mirror_the_grid])
    def total_sky(
            self,
            name=grid_name,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -c 1 -faf',
            sensor_count=sensor_count,
            sky_matrix=sky_matrix,
            sky_dome=sky_dome,
            sensor_grid=mirror_the_grid._outputs.base_file,
            conversion='0.265 0.670 0.065',  # divide by 179
            scene_file=octree_file):
        return [{
            'from': DaylightCoefficient()._outputs.result_file,
            'to': 'shortwave/initial_results/total_sky/{{self.name}}.ill'
        }]

    @task(template=SubtractSkyMatrix, needs=[total_sky, direct_sky])
    def output_matrix_math(self,
                           name=grid_name,
                           total_sky_matrix=total_sky._outputs.result_file,
                           direct_sky_matrix=direct_sky._outputs.result_file):
        return [{
            'from': SubtractSkyMatrix()._outputs.results_file,
            'to': 'shortwave/results/indirect/{{self.name}}.ill'
        }]

    @task(template=DaylightCoefficient, needs=[mirror_the_grid])
    def ground_reflected_sky(
            self,
            name=grid_name,
            radiance_parameters=radiance_parameters,
            fixed_radiance_parameters='-aa 0.0 -I -c 1',
            sensor_count=sensor_count,
            sky_matrix=sky_matrix,
            sky_dome=sky_dome,
            sensor_grid=mirror_the_grid._outputs.mirrored_file,
            conversion='0.265 0.670 0.065',  # divide by 179
            output_format='a',  # make it ascii so we expose the file as a separate output
            header='remove',  # remove header to make it process-able later
            scene_file=octree_file):
        return [{
            'from': DaylightCoefficient()._outputs.result_file,
            'to': 'shortwave/results/reflected/{{self.name}}.ill'
        }]
예제 #24
0
class CustomEnergySimEntryPoint(DAG):
    """Custom energy sim entry point."""

    # inputs
    model = Inputs.file(
        description='A Honeybee model in HBJSON file format.',
        extensions=['json', 'hbjson'],
        alias=hbjson_model_input
    )

    epw = Inputs.file(
        description='EPW weather file to be used for the energy simulation.',
        extensions=['epw']
    )

    sim_par = Inputs.file(
        description='SimulationParameter JSON that describes the settings for the '
        'simulation. Note that this SimulationParameter should usually contain '
        'design days. If it does not, the annual EPW data be used to generate '
        'default design days, which may not be as representative of the climate as '
        'those from a DDY file.', extensions=['json'], optional=True,
        alias=energy_simulation_parameter_input
    )

    additional_string = Inputs.str(
        description='An additional text string to be appended to the IDF before '
        'simulation. The input should include complete EnergyPlus objects as a '
        'single string following the IDF format. This input can be used to include '
        'EnergyPlus objects that are not currently supported by honeybee.',
        default='', alias=idf_additional_strings_input
    )

    # tasks
    @task(template=SimulateModel)
    def run_simulation(
        self, model=model, epw=epw, sim_par=sim_par,
        additional_string=additional_string
    ) -> List[Dict]:
        return [
            {'from': SimulateModel()._outputs.idf, 'to': 'model.idf'},
            {'from': SimulateModel()._outputs.sql, 'to': 'eplusout.sql'},
            {'from': SimulateModel()._outputs.zsz, 'to': 'epluszsz.csv'},
            {'from': SimulateModel()._outputs.html, 'to': 'eplustbl.htm'},
            {'from': SimulateModel()._outputs.err, 'to': 'eplusout.err'}
        ]

    # outputs
    idf = Outputs.file(
        source='model.idf', description='The IDF model used in the simulation.'
    )

    sql = Outputs.file(
        source='eplusout.sql',
        description='The result SQL file output by the simulation.'
    )

    zsz = Outputs.file(
        source='epluszsz.csv', description='The result CSV with the zone loads '
        'over the design day output by the simulation.', optional=True
    )

    html = Outputs.file(
        source='eplustbl.htm',
        description='The result HTML page with summary reports output by the simulation.'
    )

    err = Outputs.file(
        source='eplusout.err',
        description='The error report output by the simulation.'
    )
예제 #25
0
class DaylightFactorEntryPoint(DAG):
    """Daylight factor entry point."""

    # inputs
    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution',
        spec={'type': 'integer', 'minimum': 1},
        alias=sensor_count_input
    )

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing',
        default='-ab 2 -aa 0.1 -ad 2048 -ar 64',
        alias=rad_par_daylight_factor_input
    )

    grid_filter = Inputs.str(
        description='Text for a grid identifer or a pattern to filter the sensor grids '
        'of the model that are simulated. For instance, first_floor_* will simulate '
        'only the sensor grids that have an identifier that starts with '
        'first_floor_. By default, all grids in the model will be simulated.',
        default='*',
        alias=grid_filter_input
    )

    model = Inputs.file(
        description='A Honeybee model in HBJSON file format.',
        extensions=['json', 'hbjson'],
        alias=hbjson_model_input
    )

    @task(template=GenSkyWithCertainIllum)
    def generate_sky(self):
        return [
            {
                'from': GenSkyWithCertainIllum()._outputs.sky,
                'to': 'resources/100000_lux.sky'
            }
        ]

    @task(template=CreateRadianceFolderGrid)
    def create_rad_folder(
        self, input_model=model, grid_filter=grid_filter
            ):
        """Translate the input model to a radiance folder."""
        return [
            {'from': CreateRadianceFolderGrid()._outputs.model_folder, 'to': 'model'},
            {
                'from': CreateRadianceFolderGrid()._outputs.model_sensor_grids_file,
                'to': 'results/grids_info.json'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
                'description': 'Sensor grids information.'
            }
        ]

    @task(
        template=CreateOctreeWithSky, needs=[generate_sky, create_rad_folder]
    )
    def create_octree(
        self, model=create_rad_folder._outputs.model_folder,
        sky=generate_sky._outputs.sky
    ):
        """Create octree from radiance folder and sky."""
        return [
            {
                'from': CreateOctreeWithSky()._outputs.scene_file,
                'to': 'resources/scene.oct'
            }
        ]

    @task(
        template=DaylightFactorRayTracing,
        needs=[create_rad_folder, create_octree],
        loop=create_rad_folder._outputs.sensor_grids,
        sub_folder='initial_results/{{item.name}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid': 'grid/{{item.full_id}}.pts'}  # sub_path for sensor_grid arg
    )
    def daylight_factor_ray_tracing(
        self,
        sensor_count=sensor_count,
        radiance_parameters=radiance_parameters,
        octree_file=create_octree._outputs.scene_file,
        grid_name='{{item.full_id}}',
        sensor_grid=create_rad_folder._outputs.model_folder
    ):
        # this task doesn't return a file for each loop.
        # instead we access the results folder directly as an output
        pass

    results = Outputs.folder(
        source='results', description='Folder with raw result files (.res) that contain '
        'daylight factor values for each sensor.', alias=daylight_factor_results
    )
예제 #26
0
class AnnualDaylightEntryPoint(DAG):
    """Annual daylight entry point."""

    # inputs
    north = Inputs.float(
        default=0,
        description='A number for rotation from north.',
        spec={'type': 'number', 'minimum': 0, 'maximum': 360},
        alias=north_input
    )

    cpu_count = Inputs.int(
        default=50,
        description='The maximum number of CPUs for parallel execution. This will be '
        'used to determine the number of sensors run by each worker.',
        spec={'type': 'integer', 'minimum': 1},
        alias=cpu_count
    )

    min_sensor_count = Inputs.int(
        description='The minimum number of sensors in each sensor grid after '
        'redistributing the sensors based on cpu_count. This value takes '
        'precedence over the cpu_count and can be used to ensure that '
        'the parallelization does not result in generating unnecessarily small '
        'sensor grids. The default value is set to 1, which means that the '
        'cpu_count is always respected.', default=1,
        spec={'type': 'integer', 'minimum': 1},
        alias=min_sensor_count_input
    )

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05',
        alias=rad_par_annual_input
    )

    grid_filter = Inputs.str(
        description='Text for a grid identifier or a pattern to filter the sensor grids '
        'of the model that are simulated. For instance, first_floor_* will simulate '
        'only the sensor grids that have an identifier that starts with '
        'first_floor_. By default, all grids in the model will be simulated.',
        default='*',
        alias=grid_filter_input
    )

    model = Inputs.file(
        description='A Honeybee model in HBJSON file format.',
        extensions=['json', 'hbjson'],
        alias=hbjson_model_grid_input
    )

    wea = Inputs.file(
        description='Wea file.',
        extensions=['wea'],
        alias=wea_input_timestep_check
    )

    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.',
        extensions=['txt', 'csv'], optional=True, alias=schedule_csv_input
    )

    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 default 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',
        alias=daylight_thresholds_input
    )

    @task(template=CreateSunMatrix)
    def generate_sunpath(self, north=north, wea=wea):
        """Create sunpath for sun-up-hours."""
        return [
            {'from': CreateSunMatrix()._outputs.sunpath,
             'to': 'resources/sunpath.mtx'},
            {
                'from': CreateSunMatrix()._outputs.sun_modifiers,
                'to': 'resources/suns.mod'
            }
        ]

    @task(template=CreateRadianceFolderGrid)
    def create_rad_folder(self, input_model=model, grid_filter=grid_filter):
        """Translate the input model to a radiance folder."""
        return [
            {
                'from': CreateRadianceFolderGrid()._outputs.model_folder,
                'to': 'model'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.bsdf_folder,
                'to': 'model/bsdf'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.sensor_grids_file,
                'to': 'results/total/grids_info.json'
            },
            {
                'from': CreateRadianceFolderGrid()._outputs.sensor_grids,
                'description': 'Sensor grids information.'
            }
        ]

    @task(template=Copy, needs=[create_rad_folder])
    def copy_grid_info(self, src=create_rad_folder._outputs.sensor_grids_file):
        return [
            {
                'from': Copy()._outputs.dst,
                'to': 'results/direct/grids_info.json'
            }
        ]

    @task(template=CreateOctree, needs=[create_rad_folder])
    def create_octree(self, model=create_rad_folder._outputs.model_folder):
        """Create octree from radiance folder."""
        return [
            {
                'from': CreateOctreeWithSky()._outputs.scene_file,
                'to': 'resources/scene.oct'
            }
        ]

    @task(
        template=SplitGridFolder, needs=[create_rad_folder],
        sub_paths={'input_folder': 'grid'}
    )
    def split_grid_folder(
        self, input_folder=create_rad_folder._outputs.model_folder,
        cpu_count=cpu_count, cpus_per_grid=3, min_sensor_count=min_sensor_count
    ):
        """Split sensor grid folder based on the number of CPUs"""
        return [
            {
                'from': SplitGridFolder()._outputs.output_folder,
                'to': 'resources/grid'
            },
            {
                'from': SplitGridFolder()._outputs.dist_info,
                'to': 'initial_results/final/total/_redist_info.json'
            },
            {
                'from': SplitGridFolder()._outputs.sensor_grids,
                'description': 'Sensor grids information.'
            }
        ]

    @task(template=Copy, needs=[split_grid_folder])
    def copy_redist_info(self, src=split_grid_folder._outputs.dist_info):
        return [
            {
                'from': Copy()._outputs.dst,
                'to': 'initial_results/final/direct/_redist_info.json'
            }
        ]

    @task(
        template=CreateOctreeWithSky, needs=[
            generate_sunpath, create_rad_folder]
    )
    def create_octree_with_suns(
        self, model=create_rad_folder._outputs.model_folder,
        sky=generate_sunpath._outputs.sunpath
    ):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [
            {
                'from': CreateOctreeWithSky()._outputs.scene_file,
                'to': 'resources/scene_with_suns.oct'
            }
        ]

    @task(template=CreateSkyDome)
    def create_sky_dome(self):
        """Create sky dome for daylight coefficient studies."""
        return [
            {'from': CreateSkyDome()._outputs.sky_dome, 'to': 'resources/sky.dome'}
        ]

    @task(template=CreateSkyMatrix)
    def create_total_sky(self, north=north, wea=wea, sun_up_hours='sun-up-hours'):
        return [
            {'from': CreateSkyMatrix()._outputs.sky_matrix,
             'to': 'resources/sky.mtx'}
        ]

    @task(template=CreateSkyMatrix)
    def create_direct_sky(
        self, north=north, wea=wea, sky_type='sun-only', sun_up_hours='sun-up-hours'
    ):
        return [
            {
                'from': CreateSkyMatrix()._outputs.sky_matrix,
                'to': 'resources/sky_direct.mtx'
            }
        ]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(self, sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        return [
            {
                'from': ParseSunUpHours()._outputs.sun_up_hours,
                'to': 'results/total/sun-up-hours.txt'
            }
        ]

    @task(template=Copy, needs=[parse_sun_up_hours])
    def copy_sun_up_hours(self, src=parse_sun_up_hours._outputs.sun_up_hours):
        return [
            {
                'from': Copy()._outputs.dst,
                'to': 'results/direct/sun-up-hours.txt'
            }
        ]

    @task(
        template=AnnualDaylightRayTracing,
        needs=[
            create_sky_dome, create_octree_with_suns, create_octree, generate_sunpath,
            create_total_sky, create_direct_sky, create_rad_folder, split_grid_folder
        ],
        loop=split_grid_folder._outputs.sensor_grids,
        # create a subfolder for each grid
        sub_folder='initial_results/{{item.full_id}}',
        # sensor_grid sub_path
        sub_paths={'sensor_grid': '{{item.full_id}}.pts'}
    )
    def annual_daylight_raytracing(
        self,
        radiance_parameters=radiance_parameters,
        octree_file_with_suns=create_octree_with_suns._outputs.scene_file,
        octree_file=create_octree._outputs.scene_file,
        grid_name='{{item.full_id}}',
        sensor_grid=split_grid_folder._outputs.output_folder,
        sensor_count='{{item.count}}',
        sky_matrix=create_total_sky._outputs.sky_matrix,
        sky_dome=create_sky_dome._outputs.sky_dome,
        sky_matrix_direct=create_direct_sky._outputs.sky_matrix,
        sunpath=generate_sunpath._outputs.sunpath,
        sun_modifiers=generate_sunpath._outputs.sun_modifiers,
        bsdfs=create_rad_folder._outputs.bsdf_folder
    ):
        pass

    @task(
        template=MergeFolderData,
        needs=[annual_daylight_raytracing]
    )
    def restructure_results(
        self, input_folder='initial_results/final/total', extension='ill'
    ):
        return [
            {
                'from': MergeFolderData()._outputs.output_folder,
                'to': 'results/total'
            }
        ]

    @task(
        template=MergeFolderData,
        needs=[annual_daylight_raytracing]
    )
    def restructure_direct_results(
        self, input_folder='initial_results/final/direct',
        extension='ill'
    ):
        return [
            {
                'from': MergeFolderData()._outputs.output_folder,
                'to': 'results/direct'
            }
        ]

    @task(
        template=AnnualDaylightMetrics,
        needs=[parse_sun_up_hours, annual_daylight_raytracing, restructure_results]
    )
    def calculate_annual_metrics(
        self, folder='results/total', schedule=schedule, thresholds=thresholds
    ):
        return [
            {
                'from': AnnualDaylightMetrics()._outputs.annual_metrics,
                'to': 'metrics'
            }
        ]

    results = Outputs.folder(
        source='results/total', description='Folder with raw result files (.ill) that '
        'contain illuminance matrices for each sensor at each timestep of the analysis.',
        alias=annual_daylight_results
    )

    results_direct = Outputs.folder(
        source='results/direct', description='Folder with raw result files (.ill) that '
        'contain matrices for just the direct illuminance.',
        alias=annual_daylight_direct_results
    )

    metrics = Outputs.folder(
        source='metrics', description='Annual metrics folder.'
    )

    da = Outputs.folder(
        source='metrics/da', description='Daylight autonomy results.',
        alias=daylight_autonomy_results
    )

    cda = Outputs.folder(
        source='metrics/cda', description='Continuous daylight autonomy results.',
        alias=continuous_daylight_autonomy_results
    )

    udi = Outputs.folder(
        source='metrics/udi', description='Useful daylight illuminance results.',
        alias=udi_results
    )

    udi_lower = Outputs.folder(
        source='metrics/udi_lower', description='Results for the percent of time that '
        'is below the lower threshold of useful daylight illuminance.',
        alias=udi_lower_results
    )

    udi_upper = Outputs.folder(
        source='metrics/udi_upper', description='Results for the percent of time that '
        'is above the upper threshold of useful daylight illuminance.',
        alias=udi_upper_results
    )
예제 #27
0
class AnnualDaylightEntryPoint(DAG):
    """Annual daylight entry point."""

    # inputs
    north = Inputs.float(
        default=0,
        description='A number for rotation from north.',
        spec={'type': 'number', 'minimum': 0, 'maximum': 360},
        alias=north_input
    )

    sensor_count = Inputs.int(
        default=200,
        description='The maximum number of grid points per parallel execution.',
        spec={'type': 'integer', 'minimum': 1}
    )

    radiance_parameters = Inputs.str(
        description='The radiance parameters for ray tracing.',
        default='-ab 2 -ad 5000 -lw 2e-05'
    )

    sensor_grid = Inputs.str(
        description='A grid name or a pattern to filter the sensor grids. By default '
        'all the grids in HBJSON model will be exported.', default='*'
    )

    model = Inputs.file(
        description='A Honeybee model in HBJSON file format.',
        extensions=['json', 'hbjson'],
        alias=hbjson_model_input
    )

    wea = Inputs.file(
        description='Wea file.',
        extensions=['wea'],
        alias=wea_input
    )

    @task(template=CreateSunMatrix)
    def generate_sunpath(self, north=north, wea=wea):
        """Create sunpath for sun-up-hours."""
        return [
            {'from': CreateSunMatrix()._outputs.sunpath, 'to': 'resources/sunpath.mtx'},
            {
                'from': CreateSunMatrix()._outputs.sun_modifiers,
                'to': 'resources/suns.mod'
            }
        ]

    @task(template=CreateRadianceFolder)
    def create_rad_folder(self, input_model=model, sensor_grid=sensor_grid):
        """Translate the input model to a radiance folder."""
        return [
            {'from': CreateRadianceFolder()._outputs.model_folder, 'to': 'model'},
            {
                'from': CreateRadianceFolder()._outputs.sensor_grids_file,
                'to': 'results/grids_info.json'
            },
            {
                'from': CreateRadianceFolder()._outputs.sensor_grids,
                'description': 'Sensor grids information.'
            }
        ]

    @task(template=CreateOctree, needs=[create_rad_folder])
    def create_octree(self, model=create_rad_folder._outputs.model_folder):
        """Create octree from radiance folder."""
        return [
            {
                'from': CreateOctreeWithSky()._outputs.scene_file,
                'to': 'resources/scene.oct'
            }
        ]

    @task(
        template=CreateOctreeWithSky, needs=[generate_sunpath, create_rad_folder]
    )
    def create_octree_with_suns(
        self, model=create_rad_folder._outputs.model_folder,
        sky=generate_sunpath._outputs.sunpath
    ):
        """Create octree from radiance folder and sunpath for direct studies."""
        return [
            {
                'from': CreateOctreeWithSky()._outputs.scene_file,
                'to': 'resources/scene_with_suns.oct'
            }
        ]

    @task(template=CreateSkyDome)
    def create_sky_dome(self):
        """Create sky dome for daylight coefficient studies."""
        return [
            {'from': CreateSkyDome()._outputs.sky_dome, 'to': 'resources/sky.dome'}
        ]

    @task(template=CreateSkyMatrix)
    def create_total_sky(self, north=north, wea=wea, sun_up_hours='sun-up-hours'):
        return [
            {'from': CreateSkyMatrix()._outputs.sky_matrix, 'to': 'resources/sky.mtx'}
        ]

    @task(template=CreateSkyMatrix)
    def create_direct_sky(
        self, north=north, wea=wea, sky_type='sun-only', sun_up_hours='sun-up-hours'
            ):
        return [
            {
                'from': CreateSkyMatrix()._outputs.sky_matrix,
                'to': 'resources/sky_direct.mtx'
            }
        ]

    @task(template=ParseSunUpHours, needs=[generate_sunpath])
    def parse_sun_up_hours(self, sun_modifiers=generate_sunpath._outputs.sun_modifiers):
        return [
            {
                'from': ParseSunUpHours()._outputs.sun_up_hours,
                'to': 'results/sun-up-hours.txt'
            }
        ]

    @task(
        template=AnnualDaylightRayTracing,
        needs=[
            create_sky_dome, create_octree_with_suns, create_octree, generate_sunpath,
            create_total_sky, create_direct_sky, create_rad_folder
        ],
        loop=create_rad_folder._outputs.sensor_grids,
        sub_folder='initial_results/{{item.name}}',  # create a subfolder for each grid
        sub_paths={'sensor_grid': 'grid/{{item.full_id}}.pts'}  # sub_path for sensor_grid arg
    )
    def annual_daylight_raytracing(
        self,
        sensor_count=sensor_count,
        radiance_parameters=radiance_parameters,
        octree_file_with_suns=create_octree_with_suns._outputs.scene_file,
        octree_file=create_octree._outputs.scene_file,
        grid_name='{{item.full_id}}',
        sensor_grid=create_rad_folder._outputs.model_folder,
        sky_matrix=create_total_sky._outputs.sky_matrix,
        sky_dome=create_sky_dome._outputs.sky_dome,
        sky_matrix_direct=create_direct_sky._outputs.sky_matrix,
        sunpath=generate_sunpath._outputs.sunpath,
        sun_modifiers=generate_sunpath._outputs.sun_modifiers
    ):
        pass

    results = Outputs.folder(
        source='results',
        alias=sort_annual_daylight_results
    )