Skip to content

Commit

Permalink
fix(express): Add express version
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkelkp committed Jan 2, 2024
1 parent 3f748bf commit 6b36a3b
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 374 deletions.
31 changes: 14 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
# Irradiance
# Irradiance Express

Calculate solar irradiance (W/m2) and radiation (kWh/m2) at each time step provided by a wea file.
Irradiance Express recipe for Pollination

The fundamental calculation of this recipe is the same as that of
[Annual Daylight Enhanced](https://github.com/pollination/annual-daylight-enhanced)
in that a detailed accounting of direct sun is computed at each time step.
However, the recipe computes broadband solar irradiance in W/m2 instead of
visible illuminance in lux.
This recipe calculate the solar irradiance (W/m2) for each timestep provided in the wea
file. Nigh-time hours are filtered before running the simulation. To match the results
for each hours see the list of hours in sun-up-hours.txt.

The detailed matrices of W/m2 at each time step are stored under `results/total`.
Detailed matrices of just the direct component (W/m2) are output to `results/direct`.
The following values are also recorded for each sensor point under the `metrics` folder:
# Limitations

* `average_irradiance`: The average irradiance in W/m2 over the Wea time period
* `peak_irradiance`: The highest irradiance value in W/m2 during the Wea time period
* `cumulative_radiation`: The cumulative radiation in kWh/m2 over the Wea time period

The `peak_irradiance` value is suitable for assessing the worst-case solar load
on cooling design days or the highest radiant temperatures that occupants might
experience in over the time period of the Wea.
This recipe uses Radiance's `gendaymtx` to generate the sky. "Gendaymtx takes a weather
tape as input and produces a matrix of sky patch values using the Perez all weather
model". "If there is a sun in the description, gendaymtx will include its contribution
in the four nearest sky patches, distributing energy according to centroid proximity".
This means that the value of direct sun is diffused between these patches. This
approximation is fine for studies such as cumulative radiation or for outdoor studies
where the amount of exact direct radiation is not critical. For accurate accounting
of direct sun see the [Irradiance](https://github.com/pollination/irradiance) recipe.
4 changes: 2 additions & 2 deletions pollination/irradiance/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .entry import AnnualIrradianceEntryPoint
from .entry import SkyIrradianceEntryPoint


__pollination__ = {
'entry_point': AnnualIrradianceEntryPoint
'entry_point': SkyIrradianceEntryPoint
}
31 changes: 0 additions & 31 deletions pollination/irradiance/_postprocess.py

This file was deleted.

181 changes: 84 additions & 97 deletions pollination/irradiance/_prepare_folder.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,25 @@
"""Prepare folder DAG."""
from dataclasses import dataclass
from pollination_dsl.dag import Inputs, GroupedDAG, task, Outputs
from pollination.honeybee_radiance.sun import CreateSunMtx, ParseSunUpHours
from dataclasses import dataclass
from pollination.honeybee_radiance.translate import CreateRadianceFolderGrid
from pollination.honeybee_radiance.octree import CreateOctree, CreateOctreeWithSky
from pollination.honeybee_radiance.sky import CreateSkyDome, CreateSkyMatrix
from pollination.honeybee_radiance.grid import SplitGridFolder
from pollination.path.write import WriteInt
from pollination.path.copy import CopyFile
from pollination.honeybee_radiance.study import StudyInfo
from pollination.honeybee_radiance.octree import CreateOctree
from pollination.honeybee_radiance.sky import CreateSkyDome, CreateSkyMatrix
from pollination.honeybee_radiance.sun import CreateSunMtx, ParseSunUpHours

# input/output alias
from pollination.alias.inputs.model import hbjson_model_grid_input
from pollination.alias.inputs.wea import wea_input
from pollination.alias.inputs.north import north_input
from pollination.alias.inputs.grid import grid_filter_input, \
min_sensor_count_input, cpu_count
from pollination.alias.inputs.bool_options import visible_vs_solar_input


@dataclass
class AnnualIrradiancePrepareFolder(GroupedDAG):
"""Prepare folder for annual irradiance."""
class SkyIrradiancePrepareFolder(GroupedDAG):
"""Prepare folder for sky irradiance."""

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

output_type = Inputs.str(
description='Text for the type of irradiance output, which can be solar '
'or visible. Note that the output values will still be irradiance (W/m2) '
'when visible is selected but these irradiance values will be just for '
'the visible portion of the electromagnetic spectrum. The visible '
'irradiance values can be converted into illuminance by multiplying them '
'by the Radiance luminous efficacy factor of 179.', default='solar',
spec={'type': 'string', 'enum': ['visible', 'solar']},
alias=visible_vs_solar_input
)

north = Inputs.float(
default=0,
description='A number between -360 and 360 for the counterclockwise '
Expand Down Expand Up @@ -78,52 +57,100 @@ class AnnualIrradiancePrepareFolder(GroupedDAG):
alias=grid_filter_input
)

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

model = Inputs.file(
description='A Honeybee Model JSON file (HBJSON) or a Model pkl (HBpkl) file. '
'This can also be a zipped version of a Radiance folder, in which case this '
'recipe will simply unzip the file and simulate it as-is.',
extensions=['json', 'hbjson', 'pkl', 'hbpkl', 'zip'],
description='A Honeybee model in HBJSON file format.',
extensions=['json', 'hbjson'],
alias=hbjson_model_grid_input
)

wea = Inputs.file(
description='Wea file.', extensions=['wea', 'epw'], 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=CreateRadianceFolderGrid, annotations={'main_task': True})
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'
}
]

@task(template=CreateSunMtx)
def generate_sunpath(self, north=north, wea=wea, output_type=output_type):
"""Create sunpath for sun-up-hours."""
def generate_sunpath(self, north=north, wea=wea, output_type='solar'):
"""Create sunpath for sun-up-hours.
The sunpath is not used to calculate radiation values.
"""
return [
{
'from': CreateSunMtx()._outputs.sunpath,
'to': 'resources/sunpath.mtx'
},
{
'from': CreateSunMtx()._outputs.sun_modifiers,
'to': 'resources/sunpath.mod'
'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."""
@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': CreateRadianceFolderGrid()._outputs.model_folder,
'to': 'model'
},
{
'from': CreateRadianceFolderGrid()._outputs.sensor_grids_file,
'to': 'results/grids_info.json'
'from': ParseSunUpHours()._outputs.sun_up_hours,
'to': 'results/sun-up-hours.txt'
}
]

@task(template=CreateOctree, needs=[create_rad_folder])
def create_octree(self, model=create_rad_folder._outputs.model_folder):
def create_octree(
self, model=create_rad_folder._outputs.model_folder, black_out=black_out
):
"""Create octree from radiance folder."""
return [
{
'from': CreateOctreeWithSky()._outputs.scene_file,
'from': CreateOctree()._outputs.scene_file,
'to': 'resources/scene.oct'
}
]
Expand All @@ -134,7 +161,7 @@ def create_octree(self, model=create_rad_folder._outputs.model_folder):
)
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
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 [
Expand All @@ -144,27 +171,12 @@ def split_grid_folder(
},
{
'from': SplitGridFolder()._outputs.dist_info,
'to': 'resources/_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'
'to': 'initial_results/final/_redist_info.json'
}
]

@task(template=CreateSkyDome)
def create_sky_dome(self):
def create_sky_dome(self, sky_density=sky_density):
"""Create sky dome for daylight coefficient studies."""
return [
{
Expand All @@ -174,8 +186,9 @@ def create_sky_dome(self):
]

@task(template=CreateSkyMatrix)
def create_total_sky(
self, north=north, wea=wea, sky_type='total', output_type=output_type,
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 [
Expand All @@ -185,36 +198,6 @@ def create_total_sky(
}
]

@task(template=CreateSkyMatrix)
def create_direct_sky(
self, north=north, wea=wea, sky_type='sun-only', output_type=output_type,
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=StudyInfo)
def create_study_info(self, wea=wea, timestep=timestep):
return [
{
'from': StudyInfo()._outputs.study_info,
'to': 'results/study_info.json'
}
]

model_folder = Outputs.folder(
source='model', description='input model folder folder.'
)
Expand All @@ -223,8 +206,12 @@ def create_study_info(self, wea=wea, timestep=timestep):
source='resources', description='resources folder.'
)

sensor_grids = Outputs.list(source='resources/grid/_info.json')

results = Outputs.folder(
source='results', description='results folder.'
)

initial_results = Outputs.folder(
source='initial_results', description='initial results folder.'
)

sensor_grids = Outputs.list(source='resources/grid/_info.json')
Loading

0 comments on commit 6b36a3b

Please sign in to comment.