diff --git a/extras-requirements.txt b/extras-requirements.txt index 02cad2d..6baecb2 100644 --- a/extras-requirements.txt +++ b/extras-requirements.txt @@ -1 +1 @@ -pollination-honeybee-vtk==0.4.2 +pollination-honeybee-vtk==0.4.3 diff --git a/pollination/pmv_comfort_map/_comfort.py b/pollination/pmv_comfort_map/_comfort.py index 3e02244..8d8fd6a 100644 --- a/pollination/pmv_comfort_map/_comfort.py +++ b/pollination/pmv_comfort_map/_comfort.py @@ -72,6 +72,20 @@ class ComfortMappingEntryPoint(DAG): 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.' @@ -145,6 +159,8 @@ def create_shortwave_mrt_map( 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 diff --git a/pollination/pmv_comfort_map/_dynshade.py b/pollination/pmv_comfort_map/_dynshade.py new file mode 100644 index 0000000..a540117 --- /dev/null +++ b/pollination/pmv_comfort_map/_dynshade.py @@ -0,0 +1,98 @@ +from pollination_dsl.dag import Inputs, DAG, task +from dataclasses import dataclass +from typing import Dict, List + +from pollination.path.read import ReadJSONList + +from ._shdcontrib import ShadeContribEntryPoint + + +@dataclass +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(self, src=sensor_grids) -> List[Dict]: + return [ + { + 'from': ReadJSONList()._outputs.data, + 'description': 'Sensor grids information.' + } + ] + + @task( + template=ShadeContribEntryPoint, + needs=[read_grids], + loop=read_grids._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, + sun_modifiers=sun_modifiers, + sun_up_hours=sun_up_hours + ) -> List[Dict]: + pass diff --git a/pollination/pmv_comfort_map/_shdcontrib.py b/pollination/pmv_comfort_map/_shdcontrib.py new file mode 100644 index 0000000..a706353 --- /dev/null +++ b/pollination/pmv_comfort_map/_shdcontrib.py @@ -0,0 +1,175 @@ +from pollination_dsl.dag import Inputs, DAG, task +from dataclasses import dataclass + +from pollination.honeybee_radiance.contrib import DaylightContribution +from pollination.honeybee_radiance.coefficient import DaylightCoefficient +from pollination.honeybee_radiance.sky import SubtractSkyMatrix + + +@dataclass +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' + } + ] diff --git a/pollination/pmv_comfort_map/entry.py b/pollination/pmv_comfort_map/entry.py index 4ea18cf..3eb5812 100644 --- a/pollination/pmv_comfort_map/entry.py +++ b/pollination/pmv_comfort_map/entry.py @@ -8,12 +8,13 @@ from pollination.honeybee_energy.settings import SimParComfort, DynamicOutputs from pollination.honeybee_energy.simulate import SimulateModel -from pollination.honeybee_energy.translate import ModelOccSchedules +from pollination.honeybee_energy.translate import ModelOccSchedules, \ + ModelTransSchedules from pollination.honeybee_radiance.sun import CreateSunMatrix, ParseSunUpHours from pollination.honeybee_radiance.translate import CreateRadianceFolderGrid from pollination.honeybee_radiance.octree import CreateOctree, CreateOctreeWithSky, \ - CreateOctreeAbstractedGroups + CreateOctreeAbstractedGroups, CreateOctreeShadeTransmittance from pollination.honeybee_radiance.sky import CreateSkyDome, CreateSkyMatrix from pollination.honeybee_radiance.grid import SplitGridFolder, MergeFolderData from pollination.honeybee_radiance.viewfactor import ViewFactorModifiers @@ -36,8 +37,9 @@ thermal_condition_output, operative_or_set_output, pmv_output, env_conditions_output from ._radiance import RadianceMappingEntryPoint -from ._comfort import ComfortMappingEntryPoint from ._dynamic import DynamicContributionEntryPoint +from ._dynshade import DynamicShadeContribEntryPoint +from ._comfort import ComfortMappingEntryPoint @dataclass @@ -410,6 +412,35 @@ def create_dynamic_octrees( } ] + @task( + template=CreateOctreeShadeTransmittance, + needs=[generate_sunpath, create_rad_folder] + ) + def create_dynamic_shade_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': 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', @@ -465,6 +496,36 @@ def run_radiance_simulation( ) -> 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_dynamic_shade_octrees + ], + loop=create_dynamic_shade_octrees._outputs.scene_info, + sub_folder='radiance', + sub_paths={ + 'octree_file': '{{item.default}}', + 'octree_file_with_suns': '{{item.sun}}' + } + ) + def run_radiance_dynamic_shade_contribution( + self, + radiance_parameters=radiance_parameters, + octree_file=create_dynamic_shade_octrees._outputs.scene_folder, + octree_file_with_suns=create_dynamic_shade_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=[ @@ -501,9 +562,10 @@ def run_radiance_dynamic_contribution( @task( template=ComfortMappingEntryPoint, needs=[ - parse_sun_up_hours, create_view_factor_modifiers, create_model_occ_schedules, + 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_dynamic_contribution, run_radiance_dynamic_shade_contribution ], loop=split_grid_folder._outputs.sensor_grids, sub_folder='initial_results', @@ -528,6 +590,8 @@ def run_comfort_map( 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, diff --git a/requirements.txt b/requirements.txt index 54bd24e..ecf688d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ pollination-ladybug==0.2.1 pollination-ladybug-comfort==0.4.4 -pollination-honeybee-radiance==0.22.3 -pollination-honeybee-energy==0.3.24 -pollination-lbt-honeybee==0.1.9 +pollination-honeybee-radiance==0.22.6 +pollination-honeybee-energy==0.4.0 +pollination-lbt-honeybee==0.1.10 pollination-alias==0.10.8 pollination-path==0.3.1