From 8f734b0b795cb5302989241840cb3433f9c4e151 Mon Sep 17 00:00:00 2001 From: Mikkel Pedersen Date: Thu, 14 Apr 2022 15:18:39 +0200 Subject: [PATCH] fix(dynamic): Add dynamic simulation and calculation --- pollination/three_phase/entry.py | 47 +++--- .../two_phase/dynamic/_raytracing.py | 146 ++++++++++++++++++ .../three_phase/two_phase/dynamic/entry.py | 129 ++++++++++++++++ requirements.txt | 2 +- 4 files changed, 300 insertions(+), 24 deletions(-) create mode 100644 pollination/three_phase/two_phase/dynamic/_raytracing.py create mode 100644 pollination/three_phase/two_phase/dynamic/entry.py diff --git a/pollination/three_phase/entry.py b/pollination/three_phase/entry.py index a49240d..8d6a3a6 100644 --- a/pollination/three_phase/entry.py +++ b/pollination/three_phase/entry.py @@ -3,9 +3,10 @@ from pollination.honeybee_radiance.translate import CreateRadianceFolderGrid from pollination.honeybee_radiance.sky import CreateSkyDome, CreateSkyMatrix from pollination.honeybee_radiance.sun import CreateSunMatrix, ParseSunUpHours -from pollination.honeybee_radiance.multiphase import CreateOctreesGrids +from pollination.honeybee_radiance.multiphase import PrepareDynamic from .two_phase.entry import TwoPhaseEntryPoint +from .two_phase.dynamic.entry import DynamicGroup from .three_phase.preparation import ThreePhaseInputsPreparation from .three_phase.calculation import ThreePhaseMatrixCalculation @@ -164,42 +165,42 @@ def create_direct_sky( } ] - @task(template=CreateOctreesGrids, needs=[create_rad_folder, generate_sunpath]) - def create_octrees_grids( + @task(template=PrepareDynamic, needs=[create_rad_folder, generate_sunpath]) + def prepare_dynamic( self, model=create_rad_folder._outputs.model_folder, - sunpath=generate_sunpath._outputs.sunpath, phase='3', cpu_count=cpu_count, - cpus_per_grid=3, min_sensor_count=min_sensor_count + sunpath=generate_sunpath._outputs.sunpath, phase=3, cpu_count=cpu_count, + cpus_per_grid=3, min_sensor_count=min_sensor_count, static='include' ): return [ { - 'from': CreateOctreesGrids()._outputs.scene_folder, + 'from': PrepareDynamic()._outputs.scene_folder, 'to': 'resources/octrees' }, { - 'from': CreateOctreesGrids()._outputs.grid_folder, + 'from': PrepareDynamic()._outputs.grid_folder, 'to': 'resources/grid' }, { - 'from': CreateOctreesGrids()._outputs.scene_info + 'from': PrepareDynamic()._outputs.scene_info }, { - 'from': CreateOctreesGrids()._outputs.two_phase_info + 'from': PrepareDynamic()._outputs.two_phase_info } ] @task( - template=TwoPhaseEntryPoint, - loop=create_octrees_grids._outputs.two_phase_info, + template=DynamicGroup, + loop=prepare_dynamic._outputs.two_phase_info, needs=[ - create_rad_folder, create_octrees_grids, + create_rad_folder, prepare_dynamic, create_total_sky, create_direct_sky, create_sky_dome, generate_sunpath ], sub_folder='calcs/2_phase/{{item.identifier}}', sub_paths={ - 'octree': '{{item.octree}}', - 'octree_direct': '{{item.octree_direct}}', - 'octree_direct_sun': '{{item.octree_direct_sun}}', + 'octree_file': '{{item.octree}}', + 'octree_file_direct': '{{item.octree_direct}}', + 'octree_file_with_suns': '{{item.octree_direct_sun}}', 'sensor_grids_folder': '{{item.sensor_grids_folder}}' } ) @@ -208,10 +209,10 @@ def calculate_two_phase_matrix( identifier='{{item.identifier}}', radiance_parameters=radiance_parameters, sensor_grids_info='{{item.sensor_grids_info}}', - sensor_grids_folder=create_octrees_grids._outputs.grid_folder, - octree=create_octrees_grids._outputs.scene_folder, - octree_direct=create_octrees_grids._outputs.scene_folder, - octree_direct_sun=create_octrees_grids._outputs.scene_folder, + sensor_grids_folder=prepare_dynamic._outputs.grid_folder, + octree_file=prepare_dynamic._outputs.scene_folder, + octree_file_direct=prepare_dynamic._outputs.scene_folder, + octree_file_with_suns=prepare_dynamic._outputs.scene_folder, sky_dome=create_sky_dome._outputs.sky_dome, total_sky=create_total_sky._outputs.sky_matrix, direct_sky=create_direct_sky._outputs.sky_matrix, @@ -224,7 +225,7 @@ def calculate_two_phase_matrix( @task( template=ThreePhaseInputsPreparation, needs=[ - create_rad_folder, create_octrees_grids, + create_rad_folder, prepare_dynamic, create_total_sky, create_sky_dome ], sub_folder='calcs/3_phase/', @@ -235,7 +236,7 @@ def calculate_two_phase_matrix( def prepare_three_phase( self, model_folder=create_rad_folder._outputs.model_folder, - octree=create_octrees_grids._outputs.scene_folder, + octree=prepare_dynamic._outputs.scene_folder, sky_dome=create_sky_dome._outputs.sky_dome, bsdf_folder=create_rad_folder._outputs.bsdf_folder, dmtx_group_params=dmtx_group_params @@ -260,7 +261,7 @@ def prepare_three_phase( @task( template=ThreePhaseMatrixCalculation, needs=[ - create_rad_folder, create_octrees_grids, + create_rad_folder, prepare_dynamic, create_total_sky, create_sky_dome, prepare_three_phase ], @@ -278,7 +279,7 @@ def calculate_three_phase_matrix_total( receivers=create_rad_folder._outputs.receivers, view_mtx_rad_params=view_mtx_rad_params, daylight_mtx_rad_params=daylight_mtx_rad_params, - octree=create_octrees_grids._outputs.scene_folder, + octree=prepare_dynamic._outputs.scene_folder, sky_dome=create_sky_dome._outputs.sky_dome, sky_matrix=create_total_sky._outputs.sky_matrix, bsdf_folder=create_rad_folder._outputs.bsdf_folder, diff --git a/pollination/three_phase/two_phase/dynamic/_raytracing.py b/pollination/three_phase/two_phase/dynamic/_raytracing.py new file mode 100644 index 0000000..6a2eb2f --- /dev/null +++ b/pollination/three_phase/two_phase/dynamic/_raytracing.py @@ -0,0 +1,146 @@ +"""Raytracing DAG for annual daylight.""" + +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 AddRemoveSkyMatrix + + +@dataclass +class DynamicRayTracing(DAG): + # inputs + + radiance_parameters = Inputs.str( + description='The radiance parameters for ray tracing', + default='-ab 2 -ad 5000 -lw 2e-05' + ) + + octree_file = Inputs.file( + description='Octree that describes the scene for indirect studies. This octree ' + 'includes all the scene with default modifiers except for the aperture groups ' + 'other the one that is the source for this calculation will be blacked out.', + extensions=['oct'] + ) + + octree_file_direct = Inputs.file( + description='Octree that describes the scene for direct studies. This octree ' + 'is similar to the octree for indirect studies with the difference that the ' + 'matrials for the scene are set to black.', + extensions=['oct'] + ) + + octree_file_with_suns = Inputs.file( + description='A blacked out octree that includes the sunpath. This octree is ' + 'used for calculating the contribution from direct sunlight.', + 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, + 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=sensor_count, + modifiers=sun_modifiers, + sensor_grid=sensor_grid, + scene_file=octree_file_with_suns, + bsdf_folder=bsdfs + ): + return [ + { + 'from': DaylightContribution()._outputs.result_file, + 'to': 'direct_sunlight.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_direct, + 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/{{self.name}}.ill' + } + ] diff --git a/pollination/three_phase/two_phase/dynamic/entry.py b/pollination/three_phase/two_phase/dynamic/entry.py new file mode 100644 index 0000000..60d3b7a --- /dev/null +++ b/pollination/three_phase/two_phase/dynamic/entry.py @@ -0,0 +1,129 @@ +from pollination_dsl.dag import Inputs, DAG, task +from pollination_dsl.dag.inputs import ItemType +from dataclasses import dataclass +from pollination.honeybee_radiance.grid import MergeFolderData + +from ._raytracing import DynamicRayTracing + + +@dataclass +class DynamicGroup(DAG): + """Dynamic entry point. + + This two phase workflow also includes the extra phase for accurately calculating the + direct sunlight. + """ + + # inputs + identifier = Inputs.str( + description='Identifier for this two-phase study. This value is usually the ' + 'identifier of the aperture group or is set to __static__ for the static ' + 'apertures in the model.', default='__static__' + ) + + radiance_parameters = Inputs.str( + description='The radiance parameters for ray tracing.', + default='-ab 2 -ad 5000 -lw 2e-05' + ) + + sensor_grids_info = Inputs.list( + description='A list with sensor grids information.', + items_type=ItemType.JSONObject + ) + + sensor_grids_folder = Inputs.folder( + description='Corresponding sensor grid folder to sensor grids info.' + ) + + octree_file = Inputs.file( + description='Octree that describes the scene for indirect studies. This octree ' + 'includes all the scene with default modifiers except for the aperture groups ' + 'other the one that is the source for this calculation will be blacked out.', + extensions=['oct'] + ) + + octree_file_direct = Inputs.file( + description='Octree that describes the scene for direct studies. This octree ' + 'is similar to the octree for indirect studies with the difference that the ' + 'matrials for the scene are set to black.', + extensions=['oct'] + ) + + octree_file_with_suns = Inputs.file( + description='A blacked out octree that includes the sunpath. This octree is ' + 'used for calculating the contribution from direct sunlight.', + extensions=['oct'] + ) + + sky_dome = Inputs.file( + description='A sky dome for daylight coefficient studies.' + ) + + total_sky = Inputs.file( + description='Sky matrix with both sun and sky components.' + ) + + direct_sky = Inputs.file( + description='Sky matrix with sun only.' + ) + + sun_modifiers = Inputs.file( + description='The list of sun modifiers that are included in octree_direct_sun.' + ) + + bsdf_folder = Inputs.folder( + description='The folder from Radiance model folder that includes the BSDF files.' + 'You only need to include the in-scene BSDFs for the two phase calculation.', + optional=True + ) + + results_folder = Inputs.str( + description='An optional string to define the folder that the outputs should be ' + 'copied to. You can use this input to copy the final results to a folder other ' + 'then the subfolder for this DAG', default='results' + ) + + @task( + template=DynamicRayTracing, + loop=sensor_grids_info, + # 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 two_phase_raytracing( + self, + radiance_parameters=radiance_parameters, + octree_file=octree_file, + octree_file_direct=octree_file_direct, + octree_file_with_suns=octree_file_with_suns, + grid_name='{{item.full_id}}', + sensor_grid=sensor_grids_folder, + sensor_count='{{item.count}}', + sky_matrix=total_sky, + sky_matrix_direct=direct_sky, + sky_dome=sky_dome, + sun_modifiers=sun_modifiers, + bsdfs=bsdf_folder + ): + pass + + @task( + template=MergeFolderData, + needs=[two_phase_raytracing], + sub_paths={ + 'dist_info': '_redist_info.json' + } + ) + def restructure_results( + self, identifier=identifier, + input_folder='initial_results/final', + extension='ill', dist_info=sensor_grids_folder, + results_folder=results_folder + ): + return [ + { + 'from': MergeFolderData()._outputs.output_folder, + 'to': '{{self.results_folder}}/{{self.identifier}}' + } + ] diff --git a/requirements.txt b/requirements.txt index 92d76dc..382d11e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -pollination-honeybee-radiance==0.21.0 +pollination-honeybee-radiance==0.22.2